0

依存関係の注入に戸惑った後、DIコンテナーに依存することを心配しています。だから私は工場ですべてを結びつけると思った。しかし、非常に多くのファクトリが必要なようです (オブジェクトごとに 1 つ (?))。

今何が起こるかは次のとおりです。

class houseFactory
{
    protected $_di;

    public function __construct(\DI $di)
    {
        $this->_setDI($di)
    }

    protected function _setDI(\DI $di)
    {
        $this->_di = $di;
    }

    public function createObject()
    {
        return $this->_di->create('house');
    }
}

houseFactory は基本的に、家の作成方法を知らなくても、作成コードと呼び出しコードを結び付けます。しかし、必要なオブジェクトごとに新しいファクトリを実際に呼び出すことは本当に問題ないのでしょうか?

house は DI コンテナーだけでは簡単に解決できず、特定のルールが必要なため、今のところそう思われます。たとえば、そのインスタンスは 1 つだけ存在する必要があります (「共有」とも呼ばれます)。それらの規則は工場に送られます。

私の質問は次のとおりです。

1) これは受け入れられますか?

私は工場の膨大なコレクションを予測していますが、私の懸念は、それがやり過ぎ/巨大な欠点/本来の目的に反することになるということです.

2) 「new」キーワードの使用が実際に「OK」なのはいつですか?

ロジックを移動して、依存関係を持つ新しいオブジェクトを作成することが良い方法である理由を理解しています。しかし、それは円形に見えます。

3) 依存性注入コンテナーは、アプリケーションのどこで、どのように機能しますか?

DIコンテナを実際にどの時点から使用/呼び出しますか? DI コンテナーをアプリケーションにハードコーディングしているように見えますか? それともそれが実際のポイントですか?

私の質問があいまいでないことを願っています。

前もって感謝します。

4

1 に答える 1

0

DI の主な目的は、オブジェクトの解決/作成を担当するオブジェクトを注入するのではなく、依存関係を注入することです。houseFactoryあなたの例では、クラスを使用してクラスを取得し、それを使用したいとしますhouse(goHome メソッドの例)。

$house = $houseFactory->createObject();
$house->goHome();

実装は、呼び出し元をクラスに依存させるだけでなく、houseクラスにも依存しhouseFactoryます。これは役に立たない依存関係です。

TrueWill が言ったように、アプリケーションがオブジェクトの作成を担当する唯一の場所はcomposition root. はcomposition root、すべてのアプリケーションの開始点です。残念ながら、純粋な php クラスにはコンポジション ルートはないと思いますが、CI や Zend などの php フレームワークには存在するはずです。

でオブジェクトの作成を行う必要があるのはなぜcomposition rootですか?

  1. オブジェクト作成の範囲を非常に小さくします。コンポジション ルートには通常、アプリケーションを開始するための小さなロジックのみが含まれます。一般的な例外を処理するための他のロジックかもしれませんが、他のロジックはそうではありません。したがって、特定のビジネス ロジックが存在しないため、オブジェクトを作成しても安全です。
  2. コンポジションルートは他のクラスで作成されていません。アプリケーションのスタートアップとして呼び出されているので、そこでクラスにオブジェクトを作成しても安全です。

コンポジション ルートの詳細については、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;
}
于 2013-05-07T06:02:31.613 に答える