依赖注入——注入的正确位置

本文关键字:注入 位置 依赖 | 更新日期: 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%正确,但概念是存在的,您可以在创建组件时提供具体的依赖项。