IoC具有静态和动态依赖性

时间:2011-10-13 19:42:30

标签: c# dependency-injection inversion-of-control unity-container ioc-container

我正在尝试在我的应用中实施IoC。我有这个模型:

interface IService;
interface IComponent;

class Service : IService
    Service()

class Component : IComponent
    Component(IService service, object runtimeValue) { }

在我的应用中,我需要获得IComponent。我的应用程序使用IoC容器(Unity)。我可以在容器中注册Service,但我不能对其Component的{​​{1}} b / c进行同样的操作。根据{{​​3}},我必须使用工厂并在我需要的任何地方注入runtimeValue

IComponent

我必须能够使用容器注册工厂,因此它必须只有静态依赖项。同时,它必须能够提供创建组件所需的interface IComponentFactory IComponent CreateComponent(object runtimeValue) class ComponentProvider : IComponentProvider ComponentProvider(IComponentFactory factory) { } IComponent CreateAndCacheComponent(object runtimeValue) { _component = factory.CreateComponent(runtimeValue) return _component } // other methods 类型的服务实例 这是工厂实施。我唯一能想到的是使用IService委托作为依赖:

Func<>

...并将容器注册为静态工厂,以便它回调容器来解析服务(我在.net 2.0上使用Unity 1.2):

class ComponentFactory : IComponentFactory
    ComponentFactory(Func<IService> serviceFactoryDelegate)

    IComponent CreateComponent(object runtimeValue) {
        return new Component(serviceFactoryDelegate.Invoke(), runtimeValue)
    }

现在我可以使用容器来解析Container .Configure<IStaticFactoryConfiguration>() .RegisterFactory<Func<IService>>(container => (Func<IService>)container.Resolve<IService>) 并根据运行时值获取组件:

ComponentProvider

现在我对此有一些疑问:

  1. 我很高兴工厂打电话给// this happens inside CompositionRoot provider = Container.Resovle<IComponentProvider>() component = provider.CreateAndCacheComponent("the component") 。这个穷人的DI不是吗?

  2. 在工厂的构造函数上使用new Component(...)时,好莱坞原则是否仍然有效?我的意思是,它最终调用container.Resolve&lt;&gt; ...有点像SL。唯一的区别是代码在应用程序的容器注册部分而不是在工厂类中。

  3. 就DI和IoC而言,这个实现有什么问题吗?

3 个答案:

答案 0 :(得分:1)

  1. 不,不是。工厂的整个目的是创建一个具体类的实例。
  2. 基本上,是的,但正如我在评论中已经提到的那样,我不明白为什么这是必要的。您可以直接注入IService的实例
  3. 它比它需要的要复杂一些。为什么双重定向IComponentProvider - &gt; IComponentFactory?看起来IComponentFactory没有任何好处。

    像这样实施ComponentProvider

    class ComponentProvider : IComponentProvider
    {
        ComponentProvider(IService service) { _service = service; }
    
        IComponent CreateAndCacheComponent(object runtimeValue) {
            _component = new Component(_service, runtimeValue);
            return _component;
    }
    

    这会给你以下好处:

    1. 你摆脱了不必要的接口IComponentFactory以及相应的实现。
    2. 无需为IService
    3. 注册工厂

  4. 一般来说,你如何实现它取决于你真正需要的东西:

    “runtimeValue”在整个运行时可以是相同的,例如从设置中读取的连接字符串。在这种情况下,不需要工厂/提供者,您可以简单地新建实例并将其注册到容器中。需要IComponent的每个人在构造函数中请求一个而不是提供者。

    如果“runtimeValue”在调用CreateAndCacheComponent之间真正发生变化,那么你只会实现一个工厂并将其作为依赖关系传递。

答案 1 :(得分:1)

  1. 距离穷人的DI还有一大步,但如果你不必每次在Component的构造函数中添加新的依赖项时都不需要更改这个工厂方法,那就太好了。
  2. 这不是问题本身。想想它就像你正在注入一个匿名的工厂类。它仍然可以用于单元测试,并且绑定可以更改,因此您仍然可以获得DI的好处。但它是一个额外的抽象层,可能没有必要。在这种情况下,您仍然可以通过将IService直接注入工厂而不是Func来避免它。
  3. 通常在使用依赖项注入时,您希望注入服务而不是。您发现必须同时拥有这两者的事实可能表明您需要重新考虑您的类的API。例如,您可能应该将值传递给类上的方法而不是构造函数。如果不了解更多细节,很难说最好的方法是什么。

答案 2 :(得分:0)

问题1:在工厂中调用new没有错。您已将实例化隔离到应用程序中的一个位置;你只是把它放在工厂而不是容器里。

如果您需要模拟或更改实现,您只需模拟或更改工厂实现,而不仅仅是组件。