web-dev-qa-db-ja.com

オブザーバーパターンのDI依存サイクルを回避する方法

私のプロジェクトでは、いくつかの場所でオブザーバーパターンを使用しています。つまり、サブジェクトはオブザーバーに何かについて通知し、行動することを期待しています。被験者はこれらのオブザーバーの詳細について何も知りません。

Springでは、オブザーバーを次のように自動配線/注入しました(コンストラクター注入):

@Autowired public Subject(List<Observer> observers) {...}

これは機能し、Observerはインターフェイスであるため、SubjectからObserverへのコンパイル時の依存関係はありません。ただし、サブジェクトからオブザーバーに通知できるように、実行時の依存関係が必要です。

上記のアプローチでは、オブザーバーの推移的な依存関係の1つが主体だったため、Beanの依存関係サイクルの問題が発生しました。

これを修正するために、新しいクラスSubjectInitializerを導入しました(それに応じてSubjectを変更しました)。

@Autowired
public SubjectInitializer(Subject subject, List<Observer> observers) {
    subject.addObservers(observers);
}

SubjectInitializerは依存関係のターゲットではないため、この方法ではBeanの依存関係サイクルはありません。

しかし、この修正は私には奇妙に見えます:

  1. オブザーバーパターンはかなり頻繁に使用されるため、Springでの使用方法については多くの経験があると思います。しかし、私は何も役に立たなかった。
  2. SubjectInitializerの目的は、Subjectを初期化することです。新しいBeanを作成する(そしてシングルトンをメモリに持っている?)の方が上にあるようです。

オブザーバーインスタンスを自動配線するより良い方法はありますか?

3
C-Otto

あなたが見ているのは、鶏と卵の状況です。この場合、ケーキを持って食べることはできません。

AがBを必要とし、Bが構築時にAを必要とする場合、基本的に行き詰まっています。昔は春を使用していませんでしたが、実際にサポートされている場合は、プロパティインジェクションやリフレクションなど、舞台裏での動的なアプローチによってほぼ確実に実装されています。

デザインの純粋性/脆弱性が気になる場合は、メソッドインジェクションを検討する価値があります。つまり、おそらく、依存関係は1つまたは2つの特定の機能を実行するためにのみ必要です。その場合、依存関係がより中心的な役割を果たし、多くの場所で必要となるのとは対照的に、メソッドインジェクションは、オブジェクトの一部としてではなく、パラメーターとして必要なときにのみ導入されるため、実際にはより優れていると主張できます。それ自体が必要です。

1
joakim

問題は、コンストラクタを使用したかったことです。コンストラクターを使用して循環依存関係を作成することはできません。これは通常、良いことです。

必要なのは、BなしでAをビルドし、AありでBをビルドした後、BをAに導入できるようにするセッターです。Cを発明する必要はありません。

この問題は春とは関係ありません。それはコンストラクタのものです。

1
candied_orange