3

我刚开始进行 DI 和单元测试,遇到了一个障碍,我相信这对于那些更有经验的开发人员来说是不费吹灰之力的:

我有一个名为 MessageManager 的类,它接收数据并将其保存到数据库中。在同一个程序集(Visual Studio 中的项目)中,我创建了一个存储库接口,其中包含访问数据库所需的所有方法。该接口的具体实现在一个名为 DataAccess 的单独程序集中。

因此 DataAccess 需要对 MessageManager 的项目引用才能了解存储库接口。而MessageManager 需要对DataAccess 的项目引用,以便MessageManager 的客户端可以注入repository 接口的具体实现。这当然是不允许的

我可以将接口移动到数据访问程序集中,但我相信存储库接口应该与使用它的客户端位于同一个程序集中

那么我做错了什么?

4

7 回答 7

3

您应该将您的界面与任一程序集分开。将接口与消费者或实现者放在一起违背了拥有接口的目的。

接口的目的是允许您注入实现该接口的任何对象,无论它是否与您的 DataAccess 对象所属的程序集相同。另一方面,您需要允许 MessageManager 使用该接口,而无需使用任何具体的实现。

把你的接口放到另一个项目中,问题就解决了。

于 2008-09-18T04:21:06.867 回答
2

您只有两个选择:添加一个程序集来保存接口或将接口移动到 DataAccess 程序集中。即使您正在开发一种体系结构,其中 DataAccess 类有一天可能会被存储库接口的另一个实现者(甚至在另一个程序集中)替换,也没有理由将其从 DataAccess 程序集中排除。

于 2008-09-18T04:20:18.617 回答
1

我认为您应该将存储库接口移至 DataAccess 程序集。这样 DataAccess 就不再需要引用 MessageManager 了。

然而,这仍然很难说,因为我对你的架构几乎一无所知......

于 2008-09-18T04:18:50.617 回答
1

通常,您可以通过使用 setter 注入而不是构造函数注入来解决循环引用问题。

在伪代码中:

Foo f = new Foo();
Bar b = new Bar();
f.setBar(b);
b.setFoo(f);
于 2008-09-18T04:22:06.443 回答
1

您是否使用了控制反转容器?如果是这样,答案很简单。

程序集 A 包含:

  • 消息管理器
  • 存储库
  • ContainerA(添加 MessageManager)

程序集 B 包含(和参考的程序集 A):

  • 存储库实现 IRepository
  • ContainerB 扩展 ContainerA(添加存储库)

程序集 C(或 B)将启动应用程序/询问 MessageManager 的容器,该容器将知道如何解析 MessageManagerIRepository。

于 2008-09-18T05:32:53.013 回答
0

依赖倒置正在发挥作用:

高级模块不应依赖于低级模块。两者都应该依赖于抽象。抽象不应依赖于细节。细节应该取决于抽象。

DatAccess 程序集中的类所依赖的抽象需要位于与 DataAccess 类和该抽象的具体实现 (MessageManager) 分开的程序集中。

是的,这是更多的组件。就我个人而言,这对我来说没什么大不了的。我认为额外的组件没有很大的缺点。

于 2008-09-18T20:32:52.100 回答
-1

您可以保留当前拥有的结构(没有从 MessageManager 到导致问题的 DataAccess 的依赖关系),然后使用该类MessageManager动态加载运行时所需的具体实现。System.Reflection.Assembly

于 2008-09-18T04:34:46.723 回答