在整个应用程序中重用接口

发布于 2024-09-24 16:06:41 字数 838 浏览 8 评论 0原文

我目前正忙于重构我的应用程序中的大部分内容。主要目的是尽可能消除不同模块之间的依赖关系。我现在偶然发现以下问题:

在我的应用程序中,我有一个 GUI 模块,它定义了接口 IDataProvider。该接口需要由应用程序实现,用于向GUI模块“提供数据”。例如,可以向数据网格提供此 IDataProvider 并使用它来循环应在数据网格中显示的所有实例,并获取它们的数据。

现在有另一个模块(实际上还有更多模块),它们都需要类似的东西(如报告模块、数据库集成模块、数学求解器模块……)。此时我可以看到我可以做两件事:

  • 我可以将 IDataProvider 从 GUI 层移动到更低级别的层,并在所有其他模块中重用相同的接口。
    • 这样做的优点是应用程序可以更轻松地使用所有模块(只需实现一次数据提供程序)。
    • 缺点是我在模块和中央 IDataProvider 之间引入了依赖关系。如果有人开始使用一个模块所需的附加方法来扩展 IDataProvider,它也会开始污染其他模块。
  • 另一种选择是为每个模块提供自己的数据提供程序,并强制应用程序在想要使用所有模块时实现所有这些数据提供程序。
    • 优点是模块不依赖于公共部分
    • 缺点是我最终得到了 IGridDataProvider、IReportDataProvider、IDatabaseDataProvider、ISolverDataProvider。
    • 优点

最好的使用方法是什么?如果所有模块需要[几乎或完全]相同类型的接口,那么让所有模块依赖于相同的通用接口是否可以接受?

如果我使用相同的 IDataProvider 接口,这是否会在将来带来令人讨厌的问题(目前我还没有意识到)?

I am currently busy refactoring big parts in my application. The main purpose is to remove as much as possible dependencies between the different modules. I now stumble on the following problem:

In my application I have a GUI module that has defined an interface IDataProvider. The interface needs to be implemented by the application and is used to 'provide data' to the GUI module. E.g. a data grid can be given this IDataProvider and use it to loop over all the instances that should be shown in the data grid, and getting their data.

Now have another module (in fact quite some more modules) that all need something similar (like a reporting module, a database integration module, a mathematical solver module, ...). At this moment I can see 2 things I can do:

  • I could move IDataProvider from the GUI layer to a much lower-level layer and reuse this same interface in all the other modules.
    • This has the advantage that it becomes easier for the application to use all the modules (it only has to implement a data provider once).
    • The disadvantage is that I introduce a dependency between the modules and the central IDataProvider. If someone starts to extend IDataProvider with additional methods needed for one module, it also starts to pollute the other modules.
  • The other alternative is to give every module its own data provider, and force the application to implement all of them if it wants to use all the modules.
    • The advantage is that the modules are not dependent on a common part
    • The disadvantage is that I end up with IGridDataProvider, IReportDataProvider, IDatabaseDataProvider, ISolverDataProvider.

What's the best approach to use? Is it acceptible to make all modules dependent on the same common interface if they require [almost or completely] the same kind of interface?

If I use the same IDataProvider interface, can this give nasty problems in the future (which I am not aware of at this moment)?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

秉烛思 2024-10-01 16:06:41

为什么不做一个中间实现呢?让一些类在分解库(或其他层)中实现 IDataProvider 的重复部分(如第一种情况)。此外,每个人都需要“实现”自己的 IDataProvider (如第二种情况)。然后,您可以在各处重复使用 IDataProvider 实现,并通过创建派生类在自定义类中添加特定方法...

即:

    // Common module.
class BasicDataProvider : IDataProvider
{
public:
    // common overrides...
};

    // For modules requiring no specific methods...
typedef BasicDataProvider ReportDataProvider;

    // Database module requires "special" handling.
class DatabaseDataProvider : BasicDataProvider
{
public:
    // custom overrides...
};

Why don't you do an intermediate implementation? Have some class implement recurring parts of IDataProvider (as in the 1st case) in a factored-out library (or other layer). Also, everyone is required to "implement" their own IDataProvider (as in the 2nd case). Then, you can re-use your IDataProvider implementation all over the place and add specific methods in custom classes by creating a derived class...

I.e.:

    // Common module.
class BasicDataProvider : IDataProvider
{
public:
    // common overrides...
};

    // For modules requiring no specific methods...
typedef BasicDataProvider ReportDataProvider;

    // Database module requires "special" handling.
class DatabaseDataProvider : BasicDataProvider
{
public:
    // custom overrides...
};
挽梦忆笙歌 2024-10-01 16:06:41

对于您提到的将 IDataProvider 移动到较低级别的缺点,还有一种替代方法。

需要扩展接口的模块可以将这些扩展放入其自己的 IDataProvider 子接口中。您可以通过主动创建这些子接口来鼓励这一点。

There is an alternative to the disadvantage you cite for moving IDataProvider to a lower-level layer.

A module that wants an extended interface could put those extensions in its own sub-interface of IDataProvider. You could encourage this by pro-actively creating those sub-interfaces.

献世佛 2024-10-01 16:06:41

我不介意有多个模块依赖于一个接口,即使它不使用该接口发布的所有方法。您还可以更多地考虑接口部分的含义,而不是它的预期模块。您提到的大多数模块只需要读取访问权限。因此,您可以以这种方式分离并有另一个用于写入等。

数据层不需要知道数据的用途(这是表示层的工作)。它只需要知道如何返回它以及如何修改它。

此外,将数据提供者(也可以标记为控制器)移动到较低级别绝对没有问题,因为它可能已经实现了一些与 UI 无关的业务逻辑(例如数据一致性)。

I wouldn't mind having multiple module depending on one interface even if it doesn't use all of the methods the interface publishes. You could also think more in a meaning for part of the interface instead of for what module is it intended. Most of the module you mention only need read access. So you could separate in this way and have another for write, etc.

The data layer doesn't need to know what the data is used for(which is the job of the presentation layer). It only needs to know how to return it and how to modify it.

Moreover, there's absolutely no problem into moving the data provider(which could also be labeled as a controller) to a lower level because it's probably already implementing some business logic(like data consistency) which has nothing to do with the UI.

心凉怎暖 2024-10-01 16:06:41

如果您担心其他方法会应用于接口,您可以使用适配器模式。也就是说:

class myFoo{
public:
    Bar getBar() =0;
}

在另一个模块中:

class myBaz{
public:
    Bar getBar() =0;
}

然后将其中一个与另一个一起使用:

class MyAdaptor: public myBaz{
public:
    MyAdaptor(myFoo *_input){
        m_Foo = _input;
    }

    Bar getBar(){ return m_Foo->getBar(); }

private:
    myFoo* m_Foo;
}

这样您就可以在 myBaz 接口中实现所有内容,并且只需要在一处提供粘合。 myFoo 可以根据需要添加任意数量的附加方法,应用程序的其余部分不需要知道或关心它。

If you're worried that additional methods would be applied to an interface you can use an Adaptor pattern. That is:

class myFoo{
public:
    Bar getBar() =0;
}

and in the other module:

class myBaz{
public:
    Bar getBar() =0;
}

Then to use one with the other:

class MyAdaptor: public myBaz{
public:
    MyAdaptor(myFoo *_input){
        m_Foo = _input;
    }

    Bar getBar(){ return m_Foo->getBar(); }

private:
    myFoo* m_Foo;
}

That way you implement everything in your myBaz interface and only need to supply the glue in one place. The myFoo can have as many additional methods added to it as they want, the rest of your application need not know or care about it.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文