DIコンテナを使ったDependency Injectionを学習しており、実システムに適用するにあたって疑問が生じたため、質問します。
前提
DIの入門サイトなどでは、class Aとclass Bがあり、AがBを利用する場合、以下のようにすると説明されていると思います:
- interface IBを定義する。BはIBを実装する。
- class Aはコンストラクタ引数でIB型の変数を受け取る。これは利用するBを受け取るものであり、Aのユニットテスト時はIBのモックを指定する。
- 実システムでは、Appが(DIコンテナの機能を利用する等で)Bを生成し、Aのコンストラクタに渡す。
ここで、私が現在携わっている現行のシステムにおいて、階層化されかつ下層が動的に生成・破棄される構造があります。以降の説明のため、オブジェクトの集約関係としてObjA→ObjB→ObjC→ObjD...(以降、E, F, G...と続く)となっているとします。
現行システムでは、あるイベントを受けてObjDがObjEを生成して処理を依頼します。さらに別のイベントを受けてObjEがObjFを作ったり、ObjDがObjEを破棄したりします。もちろん、さらに下位の階層においても同じようなことが行われます。
課題
このような階層構造を持っているとき、ObjAはObjCを直接的には利用しませんので、ObjAのコンストラクタでinterface IC型の変数を受け取りたくはないと思います。単なる土管ではありますが、本来不要な依存関係が発生してしまうためです。
またDIコンテナをObjAのコンストラクタに渡してObjBまで引き回し、ObjBのコンストラクタでObjCをDIコンテナから受け取るような実装は、これはDIではなくService Locatorであるという説明をしているサイトが多くあり、避けるべき実装であると見なされていると思います。
また、利用しないオブジェクトをシステム起動時点で全部作っておくのも、リソースの無駄のように思いますので、やりたくありません。
このような深い階層を持つ設計に対してDIを適用し、各階層をユニットテスト可能にする場合、利用するインスタンスの生成と受け渡しはどのように行うべきなのでしょうか。
DIコンテナをsingletonにして、必要に応じて各レイヤで利用するのかと思ったのですが、Service Locatorの亜種のような気がしていますし、DIコンテナのセットアップが必要になるのでユニットテスト性を損なうように思います。
あなたの回答
tips
プレビュー