具有静态和动态依赖关系的IoC
本文关键字:关系 IoC 依赖 动态 静态 | 更新日期: 2023-09-27 18:11:23
我想在我的应用程序中实现IoC。我有这个模型:
interface IService;
interface IComponent;
class Service : IService
Service()
class Component : IComponent
Component(IService service, object runtimeValue) { }
在我的应用程序的某个点,我需要得到一个IComponent
。我的应用程序使用IoC容器(Unity)。我可以用容器注册Service
,但我不能为Component
b/c的依赖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<>
委托作为依赖项:
class ComponentFactory : IComponentFactory
ComponentFactory(Func<IService> serviceFactoryDelegate)
IComponent CreateComponent(object runtimeValue) {
return new Component(serviceFactoryDelegate.Invoke(), runtimeValue)
}
…并将委托注册为容器的静态工厂,以便它回调容器来解析服务(我在。net 2.0上使用Unity 1.2):
Container
.Configure<IStaticFactoryConfiguration>()
.RegisterFactory<Func<IService>>(container => (Func<IService>)container.Resolve<IService>)
现在我可以使用容器来解析ComponentProvider
并获得基于运行时值的组件:
// this happens inside CompositionRoot
provider = Container.Resovle<IComponentProvider>()
component = provider.CreateAndCacheComponent("the component")
现在我有一些问题:
我不高兴工厂打电话给
new Component(...)
。这不是穷人的DI吗?当在工厂的构造器上使用
Func<IService>
时,好莱坞原则仍然成立吗?我的意思是,它最终调用container.Resolve<>…有点像SL,唯一的区别是代码在应用程序的容器注册部分,而不是在工厂类中。这个实现有什么(其他)错误吗,就DI和IoC而言?
- 这是远离穷人的DI的一大步,但如果你不必在每次向组件的构造函数中添加新的依赖时都更改这个工厂方法,那就更好了。
- 这不是本身的问题。可以把它看作是在注入一个匿名工厂类。它仍然可以用于单元测试,并且可以更改绑定,因此您仍然可以获得DI的好处。但它是一个额外的抽象层,这可能是不必要的。在这种情况下,您仍然可以通过将
IService
直接注入工厂而不是Func
来避免它。 通常在使用依赖注入时,你希望注入服务而不是值。如果您发现两者都必须具备,这可能表明您需要重新考虑类的API。例如,也许应该将值传递给类上的方法,而不是传递给构造函数。在不了解更多细节的情况下,很难说什么是最好的方法。
- 不,它不是。工厂的全部目的就是创建一个具体类的实例。基本上,是的,但正如我在评论中已经问过的,我不明白为什么这是必要的。你可以直接注入
这比它需要的要复杂一点。为什么双重定向是
IComponentProvider
->IComponentFactory
?看起来IComponentFactory
并没有增加任何好处。这样实现
ComponentProvider
:class ComponentProvider : IComponentProvider { ComponentProvider(IService service) { _service = service; } IComponent CreateAndCacheComponent(object runtimeValue) { _component = new Component(_service, runtimeValue); return _component; }
这将给您带来以下好处:
- 去掉不必要的接口
IComponentFactory
以及相应的实现。 - 无需为
IService
注册工厂
- 去掉不必要的接口
IService
的实例一般来说,如何实现它取决于你真正需要什么:
"runtimeValue"在整个运行时可以是相同的,例如,从设置中读取的连接字符串。在这种情况下,不需要工厂/提供者,您可以简单地新建实例并将其注册到容器中。每个需要IComponent
的人都在构造函数而不是提供程序中请求一个。
如果"runtimeValue"在调用CreateAndCacheComponent
之间真的发生了变化,你只能实现一个工厂,并将其作为依赖项传递。
问题1:在工厂调用new
没有问题。您已将实例化隔离到应用程序中的一个位置;你只是把那个地方变成了工厂而不是集装箱。
如果你需要模拟或更改实现,你只需要模拟或更改工厂实现,而不是单独模拟或更改组件。