簡単な例を作成しましょう:
このコードには1つの問題があります// . -
public class MyService<br/>
{<br/>
public MyService()<br/>
{<br/>
⋮<br/>
}<br/>
public void DoSomething()<br/>
{<br/>
⋮<br/>
}<br/>
}<br/>
<br/>
// . -
public class MyWindow : Form<br/>
{<br/>
private MyService service;<br/>
public MyWindow()<br/>
{<br/>
service = new MyService();<br/>
}<br/>
}<br/>
<br/>
//
public class MyProgram<br/>
{<br/>
static void Main()<br/>
{<br/>
⋮<br/>
///
Application.Run( new MyWindow);<br/>
}<br/>
}<br/>
MyService
クラスは
MyService
クラスにあまりにも結びついています。 これは悪いので
-
MyService
から分離してMyWindow
単体テストを書くことはできません。 実際、統合テストが行われます。 -
OtherService
しない限り、OtherService
をOtherService
に置き換えることはできません。 複数のクラスがMyService
に依存している場合、それらすべてを変更する必要があります。 - サービスで設定が必要な場合、それを使用する各クラスで設定する必要があります。
つまり、問題は
operator new()
です。 依存関係を適切に制御し、単独でオブジェクトをテストできるようにするには、この演算子を拒否する必要があります。
どうやって? これがまさにIoCおよびDIパターンの機能です。 IoC(制御の反転)は、オブジェクトの制御(この場合はオブジェクトの有効期間)がコンポーネントに割り当てられるパターンです。 何らかのアウトソーシング-オブジェクトを自分で作成する代わりに(
new()
)、いわゆるオブジェクトにリクエストします。 IoCコンテナー、つまり、有能なオブジェクトを生成できる工場。
確かに、コンテナからオブジェクトのコピーを要求するたびに遅延が発生します。 これらの場合、別のパターンを使用できます。 DI(Dependency Injection)により、初期化中に必要な依存関係をコンテナーから自動的にプルできます。 つまり、IoCコンテナーを介して
MyWindow
を作成すると、DIメカニズムは、直接関与することなく
MyService
を魔法のように初期化できます。
どのように機能しますか?
プログラムにはUnityフレームワークを使用します。 開始するには、
Main()
書き換えます。その中にコンテナを作成し、DIをウィンドウに適用します。
コンテナのpublic class MyProgram<br/>
{<br/>
static void Main()<br/>
{<br/>
⋮<br/>
var uc = new UnityContainer(); <br/>
Application.Run( uc.Resolve<MyWindow>() );<br/>
}<br/>
}<br/>
Resolve()
メソッドを使用して、タイプ
MyWindow
オブジェクトの作成だけでなく、 そのすべての依存関係の自動作成も要求します。 ここで、サービス(つまり、依存する部分)の作成を自動的に取得する方法を見てみましょう。 まず、サービスインターフェイスを引き出して、後で変更できるようにします。
次に、インターフェースが使用されるようにinterface IService<br/>
{<br/>
void DoSomething();<br/>
}<br/>
<br/>
public class MyService : IService<br/>
{<br/>
⋮ //
}<br/>
MyWindow
を変更します。 コンテナが初期化するように、サービスへのリンクを追加する方法にはいくつかのオプションがあります。 それらの1つを次に示します。
あと1つだけ残っていることがありますpublic class MyWindow : Form<br/>
{<br/>
private IService service;<br/>
public MyWindow(IService service)<br/>
{<br/>
this .service = service;<br/>
}<br/>
}<br/>
IService
型のオブジェクトのリクエストで
IService
を
IService
ようにコンテナに
IService
します。
それだけです!!! これで、プログラムが起動すると、変数public class MyProgram<br/>
{<br/>
static void Main()<br/>
{<br/>
⋮<br/>
var uc = new UnityContainer();<br/>
uc.RegisterType<IService, MyService>(); <br/>
Application.Run(uc.Resolve<MyWindow>());<br/>
}<br/>
}<br/>
service
ウィンドウが自動的に初期化されます 。 これは、コンストラクター注入と呼ばれます。 コンストラクターを空のままにしたいですか? お願い:
フィールドをプロパティに変更し、public class MyWindow : Form<br/>
{<br/>
[Dependency]<br/>
public IService Service { get; set; } <br/>
<br/>
public MyWindow()<br/>
{<br/>
⋮<br/>
}<br/>
}<br/>
[Dependency]
属性でマークして、クラスを作成するときに初期化する必要があることをコンテナに示唆しました。 結果は、コンストラクターの場合と同じです。 この手法は「セッター注入」と呼ばれます。
以上です! ご清聴ありがとうございました! トピックに興味があり、サンクトペテルブルクに住んでいる場合は、明日の会議に来てください。
シリーズのパート2を読む