プロジェクトで Netty (4.0.4.Final) を使用していますが、除外する必要がある循環依存関係が発生し続けています。この質問には主に、循環依存関係を除外するという概念が含まれますが、よく知っている人のために、Netty の用語を使用します。しかし、私の問題は実際には Netty にはないので、タグ付けしないことにしました。
以下に、関連性がないと思われる部分を省略して、コードを掲載しました。
状況
aに aMyServer
を追加するクラスがあります: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
に aを追加する必要があります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
のコンストラクター引数であるa もあります。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
、関数のスコープで作成してから、その参照をandmain()
に挿入できます。もちろん、これにより、を経由する代わりに、直接変更することができます。欠点は、現在の範囲で宣言されていることです。基本的にクラスによって変更される必要があるすべてのクラス メンバーに対してこれを行う必要はありません。MyServerHandler
MyServer
MyServerHandler
MyServer
main()
Handler
作成するMyServerFactory
私が読んだ概念の 1 つは、建設と使用を分離することでした。これは非常に理にかなっているので、以下の Factory パターンの実装を試してみました。
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()
ただし、これはコードをこのFactory
クラスに移動しただけのようです。
質問
Handler
別の a を挿入したい場合はどうなりますかMyServerInitializer
- おそらく、この newは引数として anHandler
を受け入れません。この場合のためだけにInteger
新しいものを作成する必要がありますか?Factory
Factory
おそらく のインスタンスを 1 つしか作成しない を使用することは理にかなっていますMyServer
か?- この循環参照を除外するために利用できる別のオプションはありますか?
太字の質問は、StackOverflow でこれを尋ねる際の主な焦点です。ここでは、もっとシンプルな、またはもっとエレガントなものを見落としているに違いないと感じています。経験豊富なユーザーの何人かが洞察を提供できることを願っています。さらに情報が必要な場合はお知らせください。
参考資料
- 依存性注入による循環依存性の解決
- コンストラクターの循環依存と、Misko Hevery による依存性注入
- きれいなコード - Robert C. Martin によるアジャイル ソフトウェア クラフトマンシップのハンドブック
- デザイン パターン: 再利用可能なオブジェクト指向ソフトウェアの要素 (Erich Gamma et. アル