依赖注入——注入的正确位置
本文关键字:注入 位置 依赖 | 更新日期: 2023-09-27 18:03:17
在SO上看到这个答案,我对以下"原则"有点困惑:
应用好莱坞原则
好莱坞原则在DI术语中说:不要调用DI容器,它会调用你。
永远不要通过从内部调用容器来直接请求依赖项你的代码。
但是,如果我在我的DAL中有一个存储库类,并且我想将这个实例提供给TCP/IP客户端连接时创建的对象,该怎么办?我应该在什么地方打针?
现在,我有这样的内容:
// gets created when a new TCP/IP client is connected
class Worker
{
private readonly IClient client;
public Worker(IClient client)
{
// get the repository
var repo = IoC.GetInstance<IClientMessagesRepo>();
// create an object which will parse messages
var parser = new MessageParser(client);
// create an object which will save them to repo
var logger = new MessageLogger(parser, repo);
}
}
我显然不能在我的应用程序启动时创建这个实例。那么我在哪里注入回购呢?
非常感谢!
您应该努力只调用一次IoC.GetInstance()
。
因为你不能在启动时创建Worker,所以你应该创建一个WorkerFactory,并让DI容器将依赖项注入其中:
public class WorkerFactory
{
private readonly IClientMessagesRepo clientMessagesRepo;
public WorkerFactory(IClientMessagesRepo clientMessagesRepo)
{
this.clientMessagesRepo = clientMessagesRepo;
}
public Worker Create(IClient client)
{
return new Worker(client, clientMessagesRepo);
}
}
将IClientMessagesRepo
移到构造函数参数中:
public Worker(IClient client,IClientMessagesRepo clientMessagesRepo)
当然,这只是将问题移动了一点,到创建worker的地方。当然,在某些时候调用IoC容器是必要的。但在这些情况下,我宁愿通过参数传递容器,而不是从静态属性访问它。或者使用某种工厂
在你的论证中加入IClientMessagesRepo
,让IoC为你填充:
public Worker(IClient client, IClientMessagesRepo repo)
{
[...]
}
显然,您的构造函数应该做的不仅仅是创建几个局部变量,但是您明白了。
据我所知,您在IOC容器中有存储库,但没有icclient。假设您在创建worker类时可以访问IOC容器,并假设您正在使用StructureMap,您可以这样写:
IClient concreteClient = ...;
worker = container.Using<IClient>(concreteClient).GetInstance<Worker>();
这样你就告诉StructureMap使用一个特定的icclient实例,但从存储库中获取其他依赖项。
注意:自从我上次使用StructureMap以来已经有一段时间了,所以可能代码不是100%正确,但概念是存在的,您可以在创建组件时提供具体的依赖项。