Factory vs PicoContainer - IoC容器的优点

时间:2011-06-02 09:24:26

标签: design-patterns dependency-injection inversion-of-control ioc-container

我正试图打开我的想法以寻找花哨的 IoC 原则,我发现了这篇文章: Martin fowler on IoC

他提供了一些使用 PicoContainer

的示例
private MutablePicoContainer configureContainer() {
        MutablePicoContainer pico = new DefaultPicoContainer();
        Parameter[] finderParams =  {new ConstantParameter("movies1.txt")};
        pico.registerComponentImplementation(MovieFinder.class, ColonMovieFinder.class, finderParams);
        pico.registerComponentImplementation(MovieLister.class);
        return pico;
    }

然后使用示例:

public void testWithPico() {
        MutablePicoContainer pico = configureContainer();
        MovieLister lister = (MovieLister) pico.getComponentInstance(MovieLister.class);
        Movie[] movies = lister.moviesDirectedBy("Sergio Leone");
        assertEquals("Once Upon a Time in the West", movies[0].getTitle());
    }

首先想到的是:为什么要使用像PicoContainer这样复杂的东西来配置对象的创建 - 实际上应用依赖注入 - (我是.NET开发人员,所以在.NET中它可能需要当我们可以在(例如)工厂构建器中实现对象创建的相同封装时,使用反射,这很耗时),快速运算符。

另一件事: configureContainer()仍在编译中,在编译时指定了确切的类型。那么为什么不使用工厂,并在配置文件中决定使用哪个工厂?

由于我对这种方法不熟悉,我想在IoC容器的好处方面我缺少一些东西。

1 个答案:

答案 0 :(得分:1)

我刚刚更新了与此问题here相关的答案。

在.Net中,我将查看Unity Framework(来自MSFT)的文档。我也对实施注册硬编码的想法持怀疑态度,但随着时间的推移,我克服了它。主要是因为您确实可以使用基于文件的配置,您可以注册多个实现(并标记每个实现以便可以调用它们),并且通常您不会在生产中使用多个实现。

最大的好处是自动装配 - 您可以在哪里找到依赖关系。一组复杂的类的链式自动装配是非常好的,如果没有别的,因为您可以轻松地注册有问题的10个类之一的Mock实例而无需触及实现代码。这导致了以引导容器为代价的大量可测试性。对我来说这些日子,这是赌注,甚至不值得讨论。想象一下,如果Type1依赖于2,3和4,4取决于5和6,6取决于7.如果我想测试系统如何对6中的错误作出反应,我该怎么做?我需要做的就是模拟(使用像Moq这样的酷框架)Type6,注册模拟,但是对其他类使用真正的实现。

[Fact]
public void TestType6BlowingUp()
{
  IocContainer container = new IocContainer();
  container.RegisterType(Type1, Type1Impl);
  container.RegisterType(Type2, Type2Impl);
  container.RegisterType(Type3, Type3Impl);
  container.RegisterType(Type4, Type4Impl);
  container.RegisterType(Type5, Type5Impl);
  container.RegisterType(Type6, Type6Mock);
  container.RegisterType(Type7, Type7Impl);

  Type1 type1 = container.Resolve<Type1>();
  Type1Response response = type1.DoSomethingThatCallsType6Downstream();
  //Should get errorcode 500
  Assert.True("Expected ErrorCode 500", response.ErrorCode == 500);
}