我们是否有效地使用IoC?

时间:2010-03-21 21:32:13

标签: design-patterns castle-windsor ioc-container

所以我的公司使用Castle Windsor IoC container,但感觉“关闭”:

  • 所有数据类型都在代码中注册,而不是在配置文件中注册。
  • 所有数据类型都是硬编码的,以便使用一个接口实现。实际上,对于几乎所有给定的接口,只有一种实现方式。
  • 所有已注册的数据类型都有默认构造函数,因此Windsor不会为任何已注册的类型实例化对象图。

设计系统的人坚持认为IoC容器使系统更好。我们有1200多个公共类,所以它是一个 big 系统,你希望找到像Windsor这样的框架。但我仍然持怀疑态度。

我的公司是否有效地使用IoC?相对于使用new关键字的新对象,使用Windsor的新对象是否有优势?

4 个答案:

答案 0 :(得分:23)

简短回答:,贵公司没有有效使用DI。

稍长答案:主要问题是所有类都有默认构造函数。在这种情况下,那么如何解决依赖关系呢?

你的构造函数都有像这样的硬编码依赖:

public Foo()
{
    IBar bar = new Bar();
}

在这种情况下,如果不重新编译该应用程序,则无法改变依赖关系。

更糟糕的是,他们可能会使用Static Service Locator anti-pattern

public Foo()
{
    IBar bar = Container.Resolve<IBar>();
}

DI容器应该解析应用程序Composition Root中的整个依赖关系图,并且不用了。

通常,最好使用约定优于配置,在代码中使用启发式方法来配置容器。应该为少数情况保留XML配置,在这些情况下,您需要能够重新配置依赖关系而不重新编译,这应该只是一个小子集。简而言之,我认为在代码中配置容器没有固有的问题。事实上,这是首选方法。

每个接口只有一个实现也不是问题。这是一个开始,如果应用程序真正松散耦合,那就是不断打开的机会之窗。迟早你很可能会引入替代实现,但如果接口已经到位且整个代码库都遵循Liskov Substitution Principle,你最好这样做。

答案 1 :(得分:3)

  

所有数据类型都在代码中注册,而不是在配置文件中注册。

根据数据类型,我认为你的意思是绑定。例如,IFoo应与Foo绑定。如果是这样的话,那没关系。实际上,这在许多人的眼中(包括我的)比通过XML指定绑定要好得多。这里的自然好处是在编译时进行检查。你不会像他们所说的那样用XML编程

  

所有数据类型都使用硬编码   一个接口实现。事实上,   对于几乎所有给定的接口,那里   是,而且永远只会是一个   实施

你确定吗?如果是这样,这个可能是一种气味。但是你已经说过这是一个很大的应用程序。如果正在进行任何单元测试(或自动化测试),那么每个实现的接口都是完全有效的。

  

我公司是否有效使用IoC?   新人有优势吗?   与温莎的对象比新的   具有新关键字的对象?

是的,从我可以收集到的。对于任何形式的自动化测试,在对象中创建依赖项是一件坏事。通过使用IOC容器,可以在实际将生产代码连接在一起时删除类的复杂布线。这简化了应用程序,并允许您作为开发人员专注于功能和其他任务,而不是确保整个实际构建。

此外,通过反转控件,可以非常轻松地更改应用程序的模块化部分。例如,假设您希望切换模块以获得更好的版本。使用IOC容器,您只需修改一行或两行绑定即可。如果没有IOC,您必须手动遍历应用程序并确保它在内部正确连接。

这是一个很好的问题,关于你的最后一点,why you should use IOC关于直接手动方法。

答案 2 :(得分:1)

我相信其他人会发布更详细的答案,但这就是我所拥有的:

  

所有数据类型都在代码中注册,而不是在配置文件中注册。

at least some)IoC /依赖注入框架中存在一种趋势,即使用代码而不是XML Config来注册依赖项。主要的好处是你在编译时知道是否有错误连线。例如,如果您决定添加/删除构造函数参数,那么当您的配置不同步时,您的代码实际上将无法编译(并且它会使拼写错误在运行时显示为随机空引用异常)。

  

所有数据类型都是硬编码的,以便使用一个接口实现。事实上,对于几乎所有给定的接口,只有一种实现方式。

我不太确定“一个接口实现”是什么意思。如果你的意思是接口被转发到实现它们的对象,那么这肯定不是犹太教。如果没有那么编码到接口而不是具体实现有一个好处。主要的是显然能够在单元测试中使用支持所述接口的模拟对象。对接口进行编程(理论上)会强制您使代码更松散地耦合,从而有助于测试性。它还打开了一些非常酷的设计选项,例如Build a generic typesafe DAO with Hibernate and Spring AOP一个。

  

所有已注册的数据类型都有默认构造函数,因此Windsor不会为任何已注册的类型实例化对象图。

这也不一定是坏事。我认为一般来说,经验法则是如果依赖关系对于您的类执行它的函数至关重要,那么应该使用构造函数注入。如果不是(日志记录可能是最常用的例子)那么属性注入是一个更合适的选择。虽然我对Castle Windsor不熟悉,但我知道至少有些Java IoC容器在早期版本中不支持构造函数注入(如果更熟悉Castle Windsor的人可以对此发表评论,那就太棒了)。如果Castle Windsor在早期版本中没有此功能,那么这也可能导致您在系统中看到的设计。

至于在任何地方使用IoC与呼叫new,这也取决于使用情况。我所从事的少数几个项目主要依赖于IoC(Java中的Spring和.NET中的Autofac),将我所有的依赖项连接起来,让我们可以非常快速,轻松地尝试对象层次结构和组合。

答案 3 :(得分:0)

你的前两个问题不是真正的问题(Finglas描述了为什么会这样)。

我会认为“所有已注册的数据类型都有一个默认构造函数”作为代码气味(假设该类直接从您的IoC容器加载依赖项)。当发生这种情况时,1)应用程序入口点适合从Ioc容器中获取对象(因为您可能需要初始化该Ioc容器),或2)您可能正在使用工厂的地方。 / p>

不建议使用默认构造函数填充依赖项。原因是你复制了如何创建类的知识。理想情况下,每个类甚至不必知道您的IoC容器的位置 - 这就是应用程序入口点的工作。

听起来贵公司的IoC使用情况总体上并不差。