【问题标题】:Break cyclic dependency in order to use dependency injection打破循环依赖以使用依赖注入
【发布时间】:2015-01-28 11:59:17
【问题描述】:

我刚开始使用dagger 2,之前没有使用过任何其他依赖注入框架。现在我陷入了循环依赖,我不知道如何正确解决它。考虑以下服务器应用程序中的示例,它使用带有 Java NIO 的 Reactor pattern

我有一个Handler 对象附加到一个选择键上,当新信息到达网络时执行该对象:

class Handler implements Runnable {
  Server server;
  Client client;

  public void run {
    // static factory method that eventually calls a method on server, passing in 'client' as argument
    Command.parse(input).execute(server, client); 

  }

  public void send(String string) {
    // enqueu string and inform reactor about interest in sending
  }
}

Client 类保存有关已连接客户端的一些状态。所有连接的客户端都在Server 类中进行管理。

class Client {
  Handler h;

  public send(String response) {
    h.send(response);          
  }
}

当新的输入到达时,Handler 会创建Command 对象,在服务器上执行它们,服务器最终会响应客户端。

所以我现在正在做的是在Handler 中手动创建一个Client 对象,并传入一个this 引用,以便能够发送响应:

client = new Client(this);

所以我现在的问题是:设计有问题吗?是否可以解耦ClientHandler?还是我应该忍受这个而不使用依赖注入everywhere

感谢您的建议

【问题讨论】:

    标签: java dependency-injection dagger-2


    【解决方案1】:

    如果您希望客户端能够通过处理程序发回消息,那么以下可能会破坏您的循环:

    // lives in a common package both classes access
    public interface ResponseClass {
         public void sendSomeMessage(String message);
    }
    
    public class Handler { // handler can also implement ResponseClass directly but I prefer using an additional class for flexibility.
         public void whenYouCreateClient() {
             Client client = new Client(new HandlerWrapper(this)); 
         }
    
         public static class HandlerWrapper implements ResponseClass {
             private final Handler handler;
    
             public HandlerWrapper(Handler handler) { this.handler = handler; }
    
             public void sendSomeMessage(String message) {
                 handler.send(message);
             }
         }
    
         public void send(String string) {
             // enqueu string and inform reactor about interest in sending
         }
    }
    
    public class Client {
        ResponseClass rc; // naming should be improved :)
    
        public void sendMessage(String message) {
            rc.sendSomeMessage(message);
        }
    }
    

    现在运行时,您的类仍然绑定在一起,但就您的设计而言,您的客户端仅附加到通用 ResponseClass。

    你可以有这样的层次结构:

    普通

    处理程序知道客户端和常见的地方 客户只知道共同点。 (假设你把接口放在通用包里)

    而不是 客户端 处理程序

    我故意使用 sendSomeMessage 来强调它是一种在包装器/接口上调用的不同方法,但当然你可以随意命名它们。

    备注:我没有使用 dagger2,所以我不能确定使用该产品可以完成我所做的事情,但这就是我解耦这种循环依赖的方式

    【讨论】:

    • 如果我理解正确,我仍然需要在我的 Handler 对象中构造 Client 对象并传入对我自己的引用 (new Client(new HandlerWrapper(this)))。我是依赖注入的新手,但如果我理解正确,你不应该使用new 运算符。
    • @S1lentSt0rm:为了使 ClientHandler 不依赖于 DI 库,所有服务和处理程序的构建都应该在业务逻辑之外的一个单独的布线模块中完成跨度>
    • @k3b 我认为将它们连接到其他地方是我需要做的。 Handler 中唯一的公共方法是 send(String s)。额外的接口并没有增加太多的解耦。由于两者之间的依赖关系,我不能使用构造函数注入而是必须使用方法注入的假设是否正确?
    【解决方案2】:

    我意识到我真正想要解决的不是打破ClientHandler 之间的依赖关系,而是使用依赖注入而不是new 运算符。

    我一直在寻找的解决方案:将ClientFactory 注入Handler 的构造函数并使用clientFactory.create(this) 创建一个Client 对象。出色的库 AutoFactory 允许您使用简单的 @AutoFactory 注释创建这样的工厂。创建的类的构造函数会自动标注@Inject

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2010-11-29
      • 2020-03-14
      • 1970-01-01
      • 2018-03-03
      • 2020-01-29
      • 1970-01-01
      相关资源
      最近更新 更多