1

StructureMap の使用方法の一部を理解するのに苦労しています。特に、ドキュメンテーションでは、一般的なアンチパターン、コンストラクター注入の代わりにサービスロケーターとしてのみ StructureMap を使用することに関するステートメントが作成されています (Structuremap ドキュメントから直接のコードサンプル)。

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

それ以外の:

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

これは非常に短いオブジェクト グラフでは問題ありませんが、オブジェクトを何レベルも深く処理する場合、これは、より深いオブジェクトに必要なすべての依存関係を上から直接渡す必要があることを意味しますか? 確かに、これはカプセル化を破り、より深いオブジェクトの実装に関する多くの情報を公開します。

たとえば、Active Record パターンを使用しているとします。そのため、レコード自体を保存およびロードできるようにするには、データ リポジトリにアクセスする必要があります。このレコードがオブジェクト内に読み込まれる場合、そのオブジェクトは 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;
}

任意の考えをいただければ幸いです。

サイモン

編集: インジェクションは最上層から開始する必要があるという意見があるようです。ActiveRecord は OuterClass に注入される ThingThatNeedsRecord に注入されます。これに関する問題は、実行時パラメーター (たとえば、取得するレコードの ID) を使用して ActiveRecord をインスタンス化する必要がある場合です。ActiveRecord を ThingThatNeedsRecord の一番上に挿入している場合、その時点で必要な id をどうにかして把握する必要があります (これにより、最上位レイヤーが実装されるべきではありません)、または部分的に構築された ActiveRecord が必要になります。後でIDを設定します。N 個のレコードが必要で、ThingThatNeedsRecord 内のロジックを実行するまでわからない場合、これはさらに複雑になります。

4

1 に答える 1

6

コントロールの逆転は暴力のようなものです。それでも問題が解決しない場合は、十分に使用していません。またはそのようなもの

さらに言えば、コンストラクター注入を介して注入するOuterClass必要があると思います。ThingThatNeedsRecord同様に、それに注入するThingThatNeedsRecord必要があります。ActiveRecordこれは差し迫った問題を解決するだけでなく、コードをよりモジュール化してテストしやすくします。

于 2011-01-02T16:10:09.680 に答える