Factory 与 PicoContainer - IoC 容器的优点

发布于 2024-11-10 18:34:16 字数 1355 浏览 3 评论 0原文

我试图打开我的思维,接受奇特的 IoC 原则,我发现了这篇文章: Martin fowler 谈 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当我们可以在(例如)工厂构建器反射,这很耗时) strong>,具有快速的new运算符。

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

由于我是这种方法的新手,我想我在 IoC 容器的好处方面缺少一些东西。

I'm trying to open my mind for fancy IoC principle, and I came across the article:
Martin fowler on IoC

He provides some examples of using 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;
    }

and then sample usage:

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());
    }

And first thought that popped into my head is: why to use something so complicated as PicoContainer to configure creation of an object - and in fact apply Dependency Injection - (I'm .NET developer so in .NET it would probably require using Reflection, which is time consuming), when we can achieve the same encapsulation of object creation in (for instance) Factories or Builder, with fast new operator.

Another thing: configureContainer() is still compiled, exact types are specified at compile time. So why not to use factories, and decide in config file which factory to use?

As I'm new to that approach, I guess there's something I'm missing in terms of benefits of IoC Containers.

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

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

发布评论

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

评论(1

漫雪独思 2024-11-17 18:34:22

我刚刚更新了与此问题相关的答案 这里

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

最大的好处是自动装配 - 可以为您找到您的依赖项。一组复杂的类的链式自动装配非常漂亮,因为您可以轻松注册相关 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);
}

I just updated an answer related to this question here.

In .Net I would take a look at the documentation around the Unity Framework (from MSFT). I was also leery of the idea of hard-coding the implementation registrations but over time I got over it. Mainly because you can indeed use file-based configuration, you can register more than one implementation (and tag each one so they can be called upon) and typically you are not using more than one implementation in production anyways.

The biggest benefit is autowiring - where your dependencies are found for you. The chained autowiring of a complex set of classes is very nifty, if nothing else because you can easily register a Mock instance of one of the 10 classes in question without touching the implementation code. This leads to a huge amount of testability at the cost of bootstrapping a container. For me these days, it's table stakes, not even worth the discussion. Imagine if Type1 depends on 2, 3, and 4, 4 depends on 5 and 6, 6 depends on 7. If I want to test how the system reacts to an error in 6, how would I do that? All I need to do is Mock (using a cool framework like Moq) Type6, register the mock, but use real implementations for the other classes.

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