私のプロジェクトでは、いくつかの場所でオブザーバーパターンを使用しています。つまり、サブジェクトはオブザーバーに何かについて通知し、行動することを期待しています。被験者はこれらのオブザーバーの詳細について何も知りません。
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の依存関係サイクルはありません。
しかし、この修正は私には奇妙に見えます:
SubjectInitializer
の目的は、Subject
を初期化することです。新しいBeanを作成する(そしてシングルトンをメモリに持っている?)の方が上にあるようです。オブザーバーインスタンスを自動配線するより良い方法はありますか?
あなたが見ているのは、鶏と卵の状況です。この場合、ケーキを持って食べることはできません。
AがBを必要とし、Bが構築時にAを必要とする場合、基本的に行き詰まっています。昔は春を使用していませんでしたが、実際にサポートされている場合は、プロパティインジェクションやリフレクションなど、舞台裏での動的なアプローチによってほぼ確実に実装されています。
デザインの純粋性/脆弱性が気になる場合は、メソッドインジェクションを検討する価値があります。つまり、おそらく、依存関係は1つまたは2つの特定の機能を実行するためにのみ必要です。その場合、依存関係がより中心的な役割を果たし、多くの場所で必要となるのとは対照的に、メソッドインジェクションは、オブジェクトの一部としてではなく、パラメーターとして必要なときにのみ導入されるため、実際にはより優れていると主張できます。それ自体が必要です。
問題は、コンストラクタを使用したかったことです。コンストラクターを使用して循環依存関係を作成することはできません。これは通常、良いことです。
必要なのは、BなしでAをビルドし、AありでBをビルドした後、BをAに導入できるようにするセッターです。Cを発明する必要はありません。
この問題は春とは関係ありません。それはコンストラクタのものです。