依赖注入和循环引用

时间:2008-09-18 04:14:43

标签: oop tdd

我刚刚开始使用DI&单元测试并遇到了障碍,我确信这对于那些经验丰富的开发人员来说并不是一件好事:

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

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

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

那我做错了什么?

7 个答案:

答案 0 :(得分:3)

您应该将接口从任一组件中分离出来。将接口与消费者或实现者一起放置使接口失效的目的。

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

将您的界面放在另一个项目中,问题就解决了。

答案 1 :(得分:2)

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

答案 2 :(得分:2)

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

程序集A包含:

  • 给messageManager
  • IRepository
  • ContainerA(添加MessageManager)

程序集B包含(和ref的AssemblyA):

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

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

答案 3 :(得分:1)

我认为您应该将存储库接口移动到DataAccess程序集。然后DataAccess不再需要引用MessageManager。

但是,由于我对你的架构几乎一无所知,所以很难说...

答案 4 :(得分:1)

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

在伪代码中:

Foo f = new Foo();
Bar b = new Bar();
f.setBar(b);
b.setFoo(f);

答案 5 :(得分:0)

Dependency inversion正在发挥作用:

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

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

是的,这是更多的装配。就个人而言,这对我来说并不是什么大不了的事。我没有看到额外装配的重大缺点。

答案 6 :(得分:-1)

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