构造函数依赖注入的循环依赖性

时间:2013-07-30 13:11:19

标签: java factory circular-dependency code-cleanup

我在一个项目中使用Netty(4.0.4.Final),并且我一直在遇到一个我需要考虑的循环依赖。这个问题主要涉及分解循环依赖的概念,但我会在熟悉的人中使用一些Netty术语。既然我的问题实际上并不在于Netty,我决定不对其进行标记。

下面,我发布了我的代码,省略了我认为不相关的部分。

情况

我有一个MyServer课程,为ChannelInboundHandlerAdapter添加了Bootstrap

public class MyServer extends AbstractMyServer {
    private Integer someInteger; //Using Integer just for example's sake.

    public MyServer(MyServerInitializer initializer) {
        //...
        bootstrap.handler(initializer);
        //...
    }

    public void updateInteger(Integer value) {
        someInteger = value;
        //Send an update packet to another server.
    }
}

MyServerInitializer需要向ChannelInboundHandlerAdapter添加ChannelPipeline

public class MyServerInitializer extends ChannelInitializer<SocketChannel> {
    private ChannelInboundHandlerAdapter handler;

    public MyServerInitializer(ChannelInboundHandlerAdapter handler) {
        this.handler = handler;
    }

    @Override
    protected void initChannel(SocketChannel ch) throws Exception {
        ch.pipeline().addLast(
                new ObjectEncoder(),
                new ObjectDecoder(),
                handler);
    }
}

我还有一个MyServerHandler,这是我所说的MyServerInitializer的构造函数参数:

public class MyServerHandler extends ChannelInboundHandlerAdapter {
    private MyServer server;

    public MyServerHandler(MyServer server) {
        this.server = server;
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        Integer obj = (Integer) msg; //Remember just using Integer for example. Think of it as an Object rather than an Integer.
        server.updateInteger(obj);
    }
}

因此,循环依赖在初始化期间变得明显:

public static void main(String[] args) {
    //I can't set a reference to MyServer instance here because it hasn't been created yet. I want to avoid the circular dependency here.
    MyServerHandler handler = new MyServerHandler(...);
    MyServerInitializer initializer = new MyServerInitializer(handler);
    MyServer server = new MyServer(initializer);
}

可能的解决方案

重构为main()

我可以从Integer someInteger中创建MyServer,在main()函数的范围内创建它,然后将其引用注入MyServerHandler和{{1} }}。这当然会让MyServer能够直接修改它,而不必通过MyServerHandler。缺点是它现在已在MyServer范围内声明。我不想为每个可能基本上需要由main()类修改的类成员执行此操作。

创建Handler

我读到的一个概念是将构造与使用分开。这很有道理,所以我用下面的Factory模式实现了它。

MyServerFactory

但是,这似乎只是将代码从public class MyServerFactory implements AbstractFactory<MyServer> { public MyServer create() { Integer someInteger = createInteger(); MyServerHandler handler = createHandler(someInteger); MyServerInitializer initializer = createInitializer(handler); return new MyServer(initializer); } /* creator methods for the different components above. */ } 移到了此main()类。

问题

  1. 如果我想向Factory注入不同的Handler会发生什么 - 也许这个新MyServerInitializer不接受Handler作为参数。我是否必须为此案例创建一个新的Integer
  2. Factory有可能只创建Factory的单个实例是否有意义?
  3. 是否有其他选项可用于分解此循环引用?
  4. 粗体问题是我在StackOverflow上提出这个问题的主要焦点。我觉得我必须在这里忽略更简单或更优雅的东西。我希望你们中的一些更有经验的用户可以提供一些见解。如果需要更多信息,请告诉我。

    参考资料

1 个答案:

答案 0 :(得分:0)

免责声明:我对Netty了解不多,这些只是阅读您的代码时的一些想法:

我认为MyServerInitializer没有任何问题。 MyServerInitializerMyServerHandler没有任何依赖关系MyServer。没关系。如果MyServerInitializer的构造函数需要MyServerHandler而不是ChannelInboundHandlerAdapter,情况会更糟。

如果可能,您应该将MyServer的构造函数参数从MyServerInitializer更改为ChannelInitializer<SocketChannel>

问题在于MyServerHandler取决于MyServerMyServerMyServerHandler具有间接运行时依赖性。我会尝试摆脱MyServer中的MyServerHandler依赖关系。要做到这一点,你可以:

  • updateInteger()方法从MyServer移到另一个类中,我们称之为IntegerUpdaterMyServerHandler应使用IntegerUpdater代替MyServerIntegerUpdater应该不依赖MyServer。使用这种方式你就不会有任何循环依赖。

  • MyServerHandlerMyServer之间添加抽象。例如:

    public interface IntegerMessageReceiver {
      void handleMessage(Integer i);
    }
    

-

    public class MyServerHandler extends ChannelInboundHandlerAdapter {
      private List<IntegerMessageReceiver> integerMessageReceivers;

      public void addIntegerMessageReceiver(IntegerMessageReceiver imr) {
        integerMessageReceivers.add(imr);
      }

      @Override
      public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        Integer obj = (Integer) msg; 
        for (IntegerMessageReceiver imr : integerMessageReceivers) { 
          imr.handleMessage(obj);
        }
      }
    }

-

    public class MyServer extends AbstractMyServer implements IntegerMessageReceiver {
      public void handleMessage(Integer i) {
        ...
      }
      ...
    }

动初始化:

MyServerHandler handler = new MyServerHandler();
MyServerInitializer initializer = new MyServerInitializer(handler);
MyServer server = new MyServer(initializer);
handler.addIntegerMessageReceiver(server);

使用这种方法你仍然会有循环的运行时依赖性,但至少你摆脱了MyServerMyServerHandler的直接编译时依赖性。