DI の主な目的は、オブジェクトの解決/作成を担当するオブジェクトを注入するのではなく、依存関係を注入することです。houseFactory
あなたの例では、クラスを使用してクラスを取得し、それを使用したいとしますhouse
(goHome メソッドの例)。
$house = $houseFactory->createObject();
$house->goHome();
実装は、呼び出し元をクラスに依存させるだけでなく、house
クラスにも依存しhouseFactory
ます。これは役に立たない依存関係です。
TrueWill が言ったように、アプリケーションがオブジェクトの作成を担当する唯一の場所はcomposition root
. はcomposition root
、すべてのアプリケーションの開始点です。残念ながら、純粋な php クラスにはコンポジション ルートはないと思いますが、CI や Zend などの php フレームワークには存在するはずです。
でオブジェクトの作成を行う必要があるのはなぜcomposition root
ですか?
- オブジェクト作成の範囲を非常に小さくします。コンポジション ルートには通常、アプリケーションを開始するための小さなロジックのみが含まれます。一般的な例外を処理するための他のロジックかもしれませんが、他のロジックはそうではありません。したがって、特定のビジネス ロジックが存在しないため、オブジェクトを作成しても安全です。
- コンポジションルートは他のクラスで作成されていません。アプリケーションのスタートアップとして呼び出されているので、そこでクラスにオブジェクトを作成しても安全です。
コンポジション ルートの詳細については、Mark Seeman の本またはブログを参照してください。
それでは、コンポジション ルートに作成されたオブジェクトにどのようにアクセスすればよいでしょうか。
ASP.Net MVC など、一部のアプリケーションは DI を適切にサポートしていますが、ASP.Net Webform を好まないアプリケーションもあります。サポートが充実しているアプリケーションでは、クラスを から直接注入できますcomposition root
。ただし、そうでない場合は、静的クラスを介してコンポジション ルート DI コンテナーにアクセスできますが、ページのコンストラクターでのみアクセスできます。したがって、コンポジションルートへのアクセスを最小限に抑えます。
EDIT1:
これはphpで書かれたDIコンテナなしのハウスクラスの使用例です(うまくいかないかもしれません、phpでDIを使用していません)。
class houseConsumer{
protected $_house;
public function __construct(\DI $house)
{
$this->_house($house)
}
public function doSomething(){
// do something
$this->_house->goHome();
}
}
class compositionRoot{
public function main(){
$diContainer = // define the DI Container
$houseConsumer = new houseConsumer($diContainer->create('house'));
$houseConsumer->doSomething();
}
}
これは C# コンソールの例です。
public class HouseConsumer{
//constructor
public HouseConsumer(IHouse house){
this.house = house;
}
IHouse house;
public void DoSomething(){
house.GoHome();
}
}
//this is the composition root
public class Program{
public static void Main(string[] args){
List<object> diContainer = new List<object>();
//populate diComponent
HouseConsumer consumer = new HouseConsumer((IHouse)diContainer[0]);
consumer.DoSomething();
}
}
編集2:
DIコンテナは実際に「メイン」メソッドの外で使用されていますか? 「メイン」メソッドの外で新しいオブジェクトを作成するにはどうすればよいですか? 私はいくつかのオブジェクトの深さだとしましょう。そこに家を建てるにはどうすればいいですか?
上記の例は Asp.Net MVC で使用できます。この場合、ページは IOC コンテナーを使用して自動的に解決されます。残念ながら、Asp.Net Web フォームなどのページで DI コンテナーが必要な場合は、静的を使用する必要がありますが、コンストラクターでのみオブジェクトを割り当てます。例(C#で、phpでstaticの使い方がわからない)。
public class Page1 : Page{
public Page1(){
this.house = CompositionRoot.DiContainer.Create("house");
}
private IHouse house;
}
DIContainer はページのコンストラクター レベルでのみ使用されるため、この実装は依然として安全です。ただし、 Service クラスではこれを行わないでください。例:
public class Renter : IRenter{
public Renter(){
this.house = CompositionRoot.DiContainer.Create("house");
}
private IHouse house;
}
悪いデザインです。Renter クラスは DIContainer に依存しています。IHouse
それを解決するには、クラスを注入します。
public class Renter : IRenter{
public Renter(IHouse house){
this.house = house;
}
private IHouse house;
}
次に、Renter クラスの呼び出し元が house クラスを渡す必要があります。この例では、貧弱な人を使用して IRenter クラスを DIContainer に割り当てます。
Dictionary<Type, object> DiContainer = new Dictionary<Type, object>();
IHouse house = new House();
IRenter renter = new Renter(house);
DiContainer.Add(typeof(IHouse), house);
DiContainer.Add(typeof(IRenter), renter);
次に、ページで使用します。
public class Page1 : Page{
public Page1(){
this.renter = (IRenter)CompositionRoot.DiContainer[typeof(IRenter)];
}
private IRenter renter;
}