编程语言
首页 > 编程语言> > java-在IoC容器中将依赖项设置为NULL并在运行时提供依赖项是一种不好的做法吗?

java-在IoC容器中将依赖项设置为NULL并在运行时提供依赖项是一种不好的做法吗?

作者:互联网

我有一个SocketManagerclass,其中包含Socket和其他字段.在使用DI框架组成对象图的过程中,可以插入除Socket之外的所有字段.我的想法是通过将Socket保留为空并在运行时进行设置来简单地预先构建整个对象图.这将使我能够在代码中的某一点完成SocketManager实例化,并在整个程序中使用该实例(因为它已通过DI框架设置为依赖项)?这是“注入”运行时依赖项的标准方法还是不好的做法?
抽象工厂似乎不是一个好主意,原因有两个:a)每次都会创建一个不同的对象b)在我要创建对象的每个位置都需要运行时参数

让我说明一下我的问题:

SocketManager类:

public class SocketManager {
    //i'll only receive the socket at runtime
    Socket socket; 
    //this object is available at compile-time and can be injected through the DI container
    InjectableObject obj;
}

在我的代码[CodePosition1]中的某处,我将收到如下所示的套接字:

public class SocketCreator{
    SocketManager socketManager; //will be injected through DI container at startup
    Socket socket = this.serverSocket.accept();
    // at this point the socket manager is fully initialized
    socketManager.setSocket(socket); 
}

现在在其他许多地方[CodePosition2]我可以使用SocketManager依赖项

public class RandomClass {
    //injected at compile-time through DI container, but only usable after [CodePosition1]
    // was executed
    SocketManager socketManager; 
    ...
        socketManager.getSocket().doSth()
    ...
}

问题在于,直到运行时[CodePosition1]为止,SocketManager尚未完全初始化,因此除了在SocketManager上使用init()或setter来“完成” SocketManager的初始化外,我不知道其他任何方法.但是,这是一个泄漏的抽象,如本文所述:Is there a pattern for initializing objects created via a DI container

解决方法:

最好从一开始就组成完整的对象图.应该避免注入空值,因为它会使使用类复杂化.

但是,就您而言,套接字似乎不是“真正的”组件,而是运行时数据.如here所述,应避免在构造期间将运行时数据注入到对象图中.

该文章提供了两种解决此问题的解决方案,但还有更多解决方案.但是,正如您已经提到的,抽象工厂通常不是一个好的解决方案,并且this blog post在更一般的意义上描述了抽象工厂存在的问题. this book的第6.2章甚至从DI的角度更详细地讨论了抽象工厂的问题.

博客文章中给出的解决方案是使用“上下文”抽象.例如,在您的情况下,一个SocketContext接口允许您在调用消费者的方法之后以及在构建消费者的对象图之后,通过消费者获取Socket运行时值.例如:

public interface SocketContext
{
    Socket get_CurrentSocket();
}

另一种选择是使用Proxy类,该类可以隐藏真实的Socket或真实的SocketManager(取决于您可以放置​​代理的级别).这使使用者无需知道某些运行时数据需要在幕后进行初始化,并且一旦进行首次调用就可能会延迟执行.例如:

public class SocketManagerLazyProxy : SocketManager
{
    private SocketManager mananger;

    public void DoSomething()
    {
        if (manager == null) manager = new RealSocketManager(new Socket());
        manager.DoSomething();
    }   
}

另一个选项是在构建对象图之后使用属性注入设置Socket值.这使您可以在更早的时间构造对象图,并在请求进入时通过在请求进入时进行设置来设置运行时值:

void HandleRequest(RequestData data)
{
    SocketManager manager = GetSocketManagerForThisRequest();
    manager.Socket = new Socket();
    Handler handler = GetHandler(data.Name);
    handler.Handle(data);
}

标签:abstract-factory,java,design-patterns,dependency-injection
来源: https://codeday.me/bug/20191012/1897101.html