二段階初期化とプロキシ
インターフェースアセンブリと実装アセンブリを分けて、実装アセンブリの相互参照を可能にすると、相互参照してるものをnewするには二段階初期化かなんかが必要になる。二段階初期化は危険極まりないのでプロキシを使うことになるだろう。
アセンブリA(IA,IBを参照) クラスA(IAを実装、IBをメンバにもつ) アセンブリIA インターフェースIA アセンブリB(IB,IAを参照) クラスB(IBを実装、IAをメンバにもつ) アセンブリIB インターフェースIB
こんな状況があるとする。これを使用するために、
Aファクトリアセンブリ(IA,IB,Aを参照) IA Create(IB b){ new A(b); } Bファクトリアセンブリ(IA,IB,Bを参照) IB Create(IA a){ new B(a); }
こんなファクトリアセンブリを用意する。使用する側は
使う側のアセンブリ(IA,IB,Aファクトリ、Bファクトリを参照) IA a = AFactory.Create(????); IB b = BFactory.Create(????);
普通にやると作成できない。Bを作るためにはAが必要になり、Aを作るためにはBが必要になる。
プロキシを作る。
class AProxy : IA{ public IA Inner{ get; set; } public AProxy(){} //IAの処理を全部Innerに投げ渡す } class BProxy : IB{ ...(上と同じ) }
あとは普通にやればいい。
var aProxy = new AProxy(); var bProxy = new BProxy(); var b = BFactory.Create(aProxy); bProxy.Inner = b; var a = AFactory.Create(bProxy); aProxy.Inner = a;
で、プロキシはいらないからもう参照しない。
これで相互参照が作れるけど、やっぱりセッターは露出してしまう。悲しいことに。まあプロキシを捨てた後にはもう関係ないっちゃ無いのだが。まあ実装クラスを二段階初期化するよりはマシだろう。
コンストラクタでプロキシのメソッドを呼び出すと破綻する。確実にやるためには、コンストラクタでは入れたインターフェースのメソッドは呼び出さないようにしないといけない。