2017-06-30 5 views
0

.netコアを使用すると、「サービス」を登録できます。これは、わかっているように、具体的なクラスにタイプを登録できるということを意味しています。依存性注入容器のポイントは何ですか?

このように、私はDIを学び、それを実践する時期だと決めました。私はそのコンセプトを理解しており、テストでは大いに有益です。しかし、私を混乱させるのは、サービスを登録し、実際に必要かどうかという考え方です。例えば

、私が持っている場合:

public class MyClass 
{ 
    public MyClass(IDataContext) 
    { 
     ... store it 
    } 
} 

そしてこれは私がテストで偽物とmoqsを可能にする、IDataContextを実装するクラスを注入することを意味します。しかし、なぜ私はサービスを登録し、スタートアップの具体的なクラスにIDataContextをマップするのですか?ただ、他の方法では、以下のものを使用してと間違って何かがある:

DataContext dc = new DataContext(); // concrete 
var c = new MyClass(dc); 

編集

この質問はむしろ、コンストラクタでインタフェースを使用する理由よりも、コンテナ(サービス)を使用してのポイントを中心にしました。

+0

あなたは場所のint DIコンテナを持つことの目的を破っているので。 – Nkosi

+0

例えば、あなたは特定のDBMSに束縛されていませんか?例えば。たぶんあなたはマルチテナントアプリケーションを構築しており、1人のテナントは何らかの理由で別のDBMSを使用する必要があります。 –

+0

サービスとその依存関係を登録して、DIコンテナがオブジェクトグラフを水和する方法を知っているようにします。 – Nkosi

答えて

2

は今、あなたは、このコード

public class MyService 
{ 
    public void DoSomething() 
    { 
     DataContext dc = new DataContext(); // concrete 
     var c = new MyClass(dc); 
     c.DoSomething(); 
    } 
} 

を置くこれらのクラスはDataContextMyClassに強い依存関係を持っています。したがって、MyServiceを単独でテストすることはできません。クラスでは、他のクラスがどのようなことをしているか気にする必要はありません。だから私たちはインターフェイスを使用しています。これは懸念の分離です。これを達成すれば、外部コードの動作に依存することなく、単体テストの単体テストを単体テストできます。

依存関係を一箇所に登録することもより洗練されているため、すべての使用状況を調べて個別に変更するのではなく、1つの場所を変更することで依存関係を取り替えることができます。

上のコード例では、MyServiceは、DataContextMyClassの両方を使用する必要があります。代わりに、それは次のようにする必要があります:今

public class MyService 
{ 
    private readonly IMyClass _myClass; 

    public MyService(IMyClass myClass) 
    { 
     _myClass = myClass; 
    } 

    public void DoSomething() 
    { 
     _myClass.DoSomething(); 
    } 
} 

public interface IMyClass 
{ 
    void DoSomething(); 
} 

public class MyClass : IMyClass 
{ 
    private readonly IDataContext _context; 

    public MyClass(IDataContext context) 
    { 
     _context = context; 
    } 
    public void DoSomething() 
    { 
     _context.SaveSomeData(); 
    } 
} 

MyServiceそれがその仕事ではないので、それはそれを心配する必要はありません、全くDataContextに依存していません。しかし、それはIMyClassを満たす何かを必要としますが、それがどのように実装されているか気にしません。 MyService.DoSomething()は、他のコードの動作に依存せずに単体テストできます。

依存関係を満たすためにコンテナを使用していなかった場合は、クラスにハード依存関係が導入されている可能性があります。

単独での試験が重要です。複数の有限のコードをテストしている場合は単体テストではありません。これは統合テストです(さまざまな理由で独自の価値があります)。単体テストでは、有限のコードブロックが期待どおりに動作することを素早く簡単に検証できます。単体テストが通過していないときは、問題がどこにあるのかを正確に知っていて、それを見つけるために熱心に検索する必要はありません。ユニットテストが他のタイプや他のシステムに依存する場合(この場合、DataContextは特定のデータベースに固有です)、データベースに触れることなくMyServiceをテストすることはできません。これは、データベースがテストのために特定の状態になければならないことを意味します。つまり、テストが偶然ではないということです(同じ結果を繰り返し実行することはできません)。あなたはMiguel CastroによるDeep Dive into Dependency Injection and Writing Decoupled Quality Code and Testable Softwareを見る。彼が作った最も良い点は、オブジェクトのインスタンスを作成するのにnewを使用する必要がある場合、物事を密接に結合していることです。 newの使用を避け、依存性注入は、それを避けるためのパターンです。 (newを使用しても必ずしも悪くはありません。私はnewをPOCOモデルに使用するのが快適です)。

0

依存関係を手動で注入できます。しかし、これは非常に退屈な作業を得ることができます。サービスが大きくなると、より多くの依存関係が得られます。それぞれの依存関係は複数の依存関係を持つことができます。

依存関係を変更する場合は、すべての用途を調整する必要があります。 DIコンテナの主な利点の1つは、コンテナがすべての依存関係解決を行うということです。手作業は必要ありません。サービスを登録するだけで、いつでもどこでも好きな場所で利用できます。

これはあまりにもオーバーヘッドのようですが、あなたのプロジェクトが少し成長すれば、本当に感謝します。

強固に関連しており、変更される可能性が低い固定依存関係の場合、手動で注入することは問題ありません。

DI容器を使用することには別の利点があります。 DIコンテナは、サービスのライフサイクルを制御します。サービスは、シングルトン、一時的(各要求は新しいインスタンスを取得する)、または有効期間を持つことができます。

たとえば、トランザクションワークフローがある場合。スコープはトランザクションと一致する可能性があります。トランザクション中、サービスへのリクエストは同じインスタンスを返します。

次のトランザクションは新しいスコープを開き、新しいインスタンスを取得します。 これにより、1つのトランザクションのすべてのインスタンスを破棄またはコミットできますが、後続のトランザクションで前のトランザクションのリソースが使用されないようにすることができます。

0

すべてのインスタンスを手動で作成することができます。小さなプロジェクトでは、通常の練習です。あなたのプロジェクト内でクラスがリンクされている場所構成ルート、あなたがすることはコンストラクタインジェクションです。

IoCライブラリは、特にライフタイムスコープやグループ登録などの複雑なケースを考慮して、このコードを簡素化できます。

0

(オブジェクトを構築する)制御の反転

このパターンのアイデアは、あなたがオブジェクトを構築したいときにのみ、その依存関係またはパラメータについてのオブジェクトと何の種類について知っておく必要があります。


依存性注入

このパターンは、直接、例えば、コンストラクタにオブジェクトを注入するのを可能にすることによって、ステップをさらに制御パターンの反転を取っています。

この場合も、取得するオブジェクトのタイプを知るだけで、依存性コンテナがオブジェクトを挿入するだけです。

また、新しいオブジェクトが構築されているかどうか、または既に存在する参照があるかどうかを知る必要はありません。

最も一般的に使用される依存性注入の種類はコンストラクタ注入ですが、メソッドを他の場所に注入することもできます。

Seperation of concerns


は、一般的に、あなたはタイプへの依存を取り除くためのインタフェースでタイプを登録します。

これはmocking typesで非常に役に立ち、テストの際にはopen closed principleの使用に役立ちます。


Martin Fowler on "Inversion of Control Containers and the Dependency Injection pattern".