1

私はStructureMapの使い方の一部を理解するのに苦労しています。代わりのコンストラクタインジェクションとサービスロケータの使用

public ShippingScreenPresenter() 
    { 
     _service = ObjectFactory.GetInstance<IShippingService>(); 
     _repository = ObjectFactory.GetInstance<IRepository>(); 
    } 

:特に は、ドキュメント内のステートメントは、一般的なアンチパターン、サービスロケータとしてのStructureMapの使用のみの代わりにコンストラクタインジェクション(ストレートのStructureMapドキュメントからコードサンプル)について行われます。

public ShippingScreenPresenter(IShippingService service, IRepository repository) 
    { 
     _service = service; 
     _repository = repository; 
    } 

これは非常に短いオブジェクトグラフのための罰金ですが、多くのレベルの深さのオブジェクトを扱うとき、これはあなたが右の上から深いオブジェクトによって必要なすべての依存関係を伝承すべきであることを意味していますか?確かにこれはカプセル化を破り、より深いオブジェクトの実装に関する情報をあまりにも多く公開します。

アクティブレコードパターンを使用しているため、自分のレコードがデータリポジトリにアクセスして、自分自身を保存して読み込む必要があるとします。このレコードがオブジェクト内にロードされている場合、そのオブジェクトはObjectFactory.CreateInstance()を呼び出して、アクティブなレコードのコンストラクタに渡しますか?そのオブジェクトが別のオブジェクトの内部にある場合はどうなりますか? IRepositoryをそれ自身のパラメータとしてさらに上から取り入れますか?これは、現時点でデータリポジトリにアクセスしているという事実を親オブジェクトに示します。外部オブジェクトはおそらく知ってはならないものです。

public class OuterClass 
{ 
    public OuterClass(IRepository repository) 
    { 
     // Why should I know that ThingThatNeedsRecord needs a repository? 
     // that smells like exposed implementation to me, especially since 
     // ThingThatNeedsRecord doesn't use the repo itself, but passes it 
     // to the record. 
     // Also where do I create repository? Have to instantiate it somewhere 
     // up the chain of objects 
     ThingThatNeedsRecord thing = new ThingThatNeedsRecord(repository); 
     thing.GetAnswer("question"); 
    } 
} 

public class ThingThatNeedsRecord 
{ 
    public ThingThatNeedsRecord(IRepository repository) 
    { 
     this.repository = repository; 
    } 

    public string GetAnswer(string someParam) 
    { 
     // create activeRecord(s) and process, returning some result 
     // part of which contains: 
     ActiveRecord record = new ActiveRecord(repository, key); 
    } 

    private IRepository repository; 
} 

public class ActiveRecord 
{ 
    public ActiveRecord(IRepository repository) 
    { 
     this.repository = repository; 
    } 

    public ActiveRecord(IRepository repository, int primaryKey); 
    { 
     this.repositry = repository; 
     Load(primaryKey); 
    } 

    public void Save(); 

    private void Load(int primaryKey) 
    { 
     this.primaryKey = primaryKey; 
     // access the database via the repository and set someData 
    } 

    private IRepository repository; 
    private int primaryKey; 
    private string someData; 
} 

どのような考えにも感謝します。

サイモン

EDIT: 意見は、注入が最上層に開始すべきであるということのようです。 ActiveRecordは、OuterClassに注入されるThingThatNeedsRecordに注入されます。 この問題は、ActiveRecordを実行時パラメータ(たとえば取得するレコードのID)でインスタンス化する必要がある場合に発生します。 ActiveRecordをトップに置くと、何とかその位置にある必要があるIDを把握しなければなりません(トップレイヤを実装すべきでない実装に公開する)か、または部分的に構築されたActiveRecordを持たなければなりません後でIdを設定してください。これは、Nレコードが必要な場合にはさらに複雑になり、ThingThatNeedsRecordの内部でロジックが実行されるまではわかりません。

+0

可能な重複:http://stackoverflow.com/questions/4570750/dependency-injection-turtles-all-the-way-down –

+0

関連:http://stackoverflow.com/questions/2420193/dependency-injection-コンストラクタ - 狂気/ 2420245#2420245 –

答えて

6

制御の反転は暴力のようなものです。それがあなたの問題を解決しないなら、あなたはそれを十分に使っていません。またはsomething like that

さらに、OuterClassには、コンストラクタインジェクションを介してThingThatNeedsRecordが注入されている必要があります。同様にThingThatNeedsRecordActiveRecordを注入する必要があります。これはすぐに問題を解決するだけでなく、コードをモジュール化してテスト可能にします。

+0

私は元の心配に戻ると思います。 OuterClassの上にThingThatNeedsRecordを作成してActiveRecordを注入すると、OuterClassの上にあるオブジェクトはオブジェクトグラフのThingThatNeedsRecordの内部実装に公開されます。 – Simon

+0

(StructureMap)コンテナを介して 'OuterClass'を作成している場合、' OuterClass'を消費するコードは 'ThingThatNeedsRecord'への依存にさらされません。適切に設定されると、コンテナは 'OuterClass'に' ThingThatNeedsRecord'を提供するだけでなく、オブジェクトグラフの他の依存関係を再帰的に処理します。 –

+1

最終的に、最上位レベルでは、ObjectFactoryからオブジェクトを取得するサービスロケーション呼び出しが行われます。しかし、そのオブジェクトの依存関係(およびそれらの依存関係)はすべてコンテナによって満たされるため、サービスロケーション呼び出しを行うコードはそれらの依存関係を知る必要はありません。 –

関連する問題