Castle Windsor を IoC コンテナーとして使用するように既存のコードを変更しようとしています。
問題のアプリケーションはドキュメント指向です。そのため、登録時に知ることができないデータ ソースを指定するためのデータに依存するオブジェクト グラフがあり、オブジェクト グラフが解決されるたびに変更されます。container.Resolve()
ただし、この依存関係はオブジェクト グラフへのいくつかのレイヤーであるため、Windsor はインライン依存関係を伝達しないため、単に引数として渡すことはできません。
私が代わりに思いついた解決策は、型指定されたファクトリ機能を使用して、グラフ内のすべての依存関係を解決できるファクトリを生成し、Document
のコンストラクタにこのファクトリのインスタンスとデータ ソースを指定する文字列を取得させることです。ファクトリは登録時に指定され、データ ソースは解決時に指定されます。そこからコンストラクターが引き継ぎ、依存関係を解決するためにファクトリーを手動でポーリングします。結果は次のようになります。
public interface IDataSource { /* . . . */ }
public interface IWidgetRepository { /* . . . */ }
public interface IWhatsitRepository { /* . . . */ }
// Implementation generated by Windsor's typed factory facility
public interface IFactory
{
IDataSource CreateDataSource(string path);
IWidgetRepository CreateWidgetRepository(IDataSource dataSource);
IWhatsitRepository CreateWhatsitRepository(IDataSource dataSource);
void Release(IDataSource dataSource);
void Release(IWidgetRepository widgetRepository);
void Release(IWhatsitRepository whatsitRepository);
}
public class Document
{
private readonly IDataSource _dataSource;
private readonly IWidgetRepository _widgetRepository;
private readonly IWhatsitRepository _whatsitRepository;
public Document (IFactory factory, string dataSourcePath)
{
_dataSource = factory.CreateDataSource(dataSourcePath);
_widgetRepository = factory.CreateWidgetRepository(_dataSource);
_whatsitRepository = factory.CreateWhatsitRepository(_dataSource);
}
}
これは完全に機能し、Windsor が依存関係の解決を担当するという目標を達成します。または、少なくとも、登録コードを変更することで、アプリケーションを簡単に再構成できます。現時点では、作成されたものごとに 1 つの呼び出しをcontainer.Resolve()
行ってDocument
いますが、罪は 2 番目の Typed Factory で簡単に修正できると信じています。
しかし、それはまだ間違っているように感じます。Windsor は、オブジェクトの新規作成と (多少の) ライフタイムの管理を担当しています。Document
しかし、実際にはこれらの依存関係をのコンストラクターに注入しているわけではありません。代わりに、コンストラクターがそれらをファクトリーから引き出しています。さらに悪いことに、のインスタンスをIDataSource
ファクトリ メソッドに渡すことで、オブジェクト グラフの管理を担当します。それは私にとって逆転の巨大な転覆のように思えます。
それで、私は何が欠けていますか?
編集
明確にするために、私が撮影することになっていると思うのは、Document
のコンストラクターが以下のようになることです。
public Document (IDataSource dataSource, IWidgetRepository widgetRepository, IWhatsitRepository whatsitRepository)
{
_dataSource = dataSource;
_widgetRepository = widgetRepository;
_whatsitRepository = whatsitRepository;
}
このように、Windsor は、コンストラクター インジェクションを使用してすべてのオブジェクトの依存関係を提供することを直接制御します。これは実際には元のコードでコンストラクターの署名がどのように見えるかですが、container.Resolve()
インライン依存関係パラメーターを伝播しないため、Windsor で動作させることができませんでした。だから私はただすることはできません:
var document = container.Resolve<IDocument>(new { dataSourcePath = somePath }); // throws an exception
Windsor は のコンストラクターに渡さないdataSourcePath
ため、そのパスでインスタンス化された が他のコンストラクターに渡されること DataSource
を確認することはなおさらです。DataSource
別の質問への回答では、これは設計によるものであることが指摘されています。そうしないと、カップリングが発生します。インターフェイスの実装に特定の依存関係があることを義務付けたり、想定したりすべきではないため、これはノーノーです。悲しいことに、それは私が思いついたコードが間違っていると私が考える別の方法を指摘していFactory.CreateWidgetRepository()
ますFactory.CreateWhatsitRepository()
。