制御の反転(IoC)は、最初に遭遇したときに非常に混乱する可能性があります。
- それは何ですか?
- それはどの問題を解決しますか?
- いつ使用するのが適切で、いつ使用しないのですか?
制御の反転(IoC)は、最初に遭遇したときに非常に混乱する可能性があります。
回答:
Inversion of Control(IoC)およびDependency Injection(DI)パターンはすべて、コードから依存関係を削除することに関するものです。
たとえば、アプリケーションにテキストエディタコンポーネントがあり、スペルチェックを提供するとします。標準コードは次のようになります。
public class TextEditor {
private SpellChecker checker;
public TextEditor() {
this.checker = new SpellChecker();
}
}
ここで行ったことにより、TextEditor
との間に依存関係が作成されますSpellChecker
。IoCシナリオでは、代わりに次のようにします。
public class TextEditor {
private IocSpellChecker checker;
public TextEditor(IocSpellChecker checker) {
this.checker = checker;
}
}
最初のコード例では、インスタンス化SpellChecker
(this.checker = new SpellChecker();
)しています。つまり、TextEditor
クラスはクラスに直接依存していSpellChecker
ます。
2番目のコード例では、コンストラクタのシグネチャにSpellChecker
依存関係クラスを含めることで抽象化を作成してTextEditor
います(クラスの依存関係を初期化していません)。これにより、依存関係を呼び出して、次のようにTextEditorクラスに渡すことができます。
SpellChecker sc = new SpellChecker; // dependency
TextEditor textEditor = new TextEditor(sc);
これで、依存関係をシグネチャに挿入するため、TextEditor
クラスを作成するクライアントSpellChecker
が使用する実装を制御できTextEditor
ます。
制御の反転は、たとえばguiプログラムのように、プログラムがコールバックしたときに得られるものです。
たとえば、古い学校のメニューには、次のようなものがあります。
print "enter your name"
read name
print "enter your address"
read address
etc...
store in database
これにより、ユーザーインタラクションのフローを制御します。
GUIプログラムなどで、代わりに次のように言います。
when the user types in field a, store it in NAME
when the user types in field b, store it in ADDRESS
when the user clicks the save button, call StoreInDatabase
したがって、制御が逆転します...コンピュータが固定された順序でユーザー入力を受け入れる代わりに、ユーザーはデータが入力される順序と、データがデータベースに保存されるタイミングを制御します。
基本的に、イベントループ、コールバック、または実行トリガーを持つものはすべてこのカテゴリに分類されます。
制御の反転とは何ですか?
これらの簡単な2つの手順に従うと、制御の反転が完了します。
実装に使用しているテクノロジー/言語に基づいて、これらの各ステップで可能ないくつかの手法があります。
-
制御の反転(IoC)の反転部分は混乱を招くものです。なぜなら、反転は相対的な用語だからです。IoCを理解する最善の方法は、その単語を忘れることです。
-
例
what-to-do
してwhen-to-do
コントロールの反転は、懸念を分離することです。
IoCなし:ラップトップコンピューターを使用していて、誤って画面を壊してしまった そして、同じモデルのノートパソコンの画面が市場に出回っていないことがわかります。だからあなたは行き詰まっています。
IoCの場合:デスクトップコンピューターがあり、誤って画面を壊してしまいます。市場に出ているほとんどすべてのデスクトップモニターを手に入れることができ、それはデスクトップでうまく動作します。
この場合、デスクトップはIoCを正常に実装します。さまざまなタイプのモニターを受け入れますが、ラップトップは受け入れませんが、修正するには特定の画面が必要です。
Inversion of Control(またはIoC)は自由を獲得することです(結婚し、自由を失い、あなたはコントロールされています。離婚し、あなたはInversion of Controlを実装しました。それが私たちが「分離」と呼んだものです。良いコンピューターシステム非常に近い関係はお勧めしません。)柔軟性の向上(オフィスのキッチンは、きれいな水道水のみを提供します。これは、飲みたいときに選択できる唯一の選択肢です。上司は、新しいコーヒーマシンをセットアップして、Inversion of Controlを実装しました。これで、水道水またはコーヒーを選択する柔軟性。)依存性が少ない (あなたのパートナーには仕事があります、あなたには仕事がなく、あなたは経済的にあなたのパートナーに依存しているので、あなたはコントロールされています。あなたは仕事を見つけ、あなたはコントロールの反転を実装しました。良いコンピューターシステムは独立を奨励します。)
デスクトップコンピューターを使用する場合、従属(つまり、制御)されています。あなたはスクリーンの前に座ってそれを見なければなりません。キーボードを使用して入力し、マウスを使用して移動します。そして、上手に書かれたソフトウェアはあなたをさらに奴隷にすることができます。デスクトップをラップトップに置き換えると、コントロールが多少逆になります。簡単に持ち運びできます。これで、コンピューターでコンピューターを制御する代わりに、コンピューターの現在の場所を制御できます。
制御の反転を実装することにより、ソフトウェア/オブジェクトコンシューマーは、制御されたりオプションが少なくなったりする代わりに、ソフトウェア/オブジェクトよりも多くの制御/オプションを取得します。
上記のアイデアを念頭に置いてください。まだIoCの重要な部分を見逃しています。IoCのシナリオでは、ソフトウェア/オブジェクトコンシューマーは洗練されたフレームワークです。つまり、作成したコードは自分では呼び出されません。次に、この方法がWebアプリケーションに適している理由を説明します。
コードがワーカーのグループであるとします。彼らは車を作る必要があります。これらの労働者には、車を組み立てるための場所とツール(ソフトウェアフレームワーク)が必要です。伝統的なソフトウェアフレームワークは、多くのツールとガレージのようになります。したがって、労働者は自分で計画を立て、ツールを使って車を組み立てる必要があります。車を作ることは簡単な仕事ではありません、労働者が適切に計画して協力することは本当に難しいでしょう。近代的ソフトウェアフレームワークは、すべての設備と管理者が配置された現代の自動車工場のようなものです。ワーカーは計画を立てる必要はありません。マネージャー(フレームワークの一部であり、彼らは最も賢い人々であり、最も洗練された計画を立てています)は、ワーカーがいつ仕事をするかを知るために調整を支援します(フレームワークはコードを呼び出します)。ワーカーは、マネージャーが(依存性注入を使用して)提供するツールを使用するのに十分な柔軟性が必要です。
ワーカーはトップレベルでプロジェクトを管理するコントロールをマネージャー(フレームワーク)に与えます。しかし、何人かの専門家に手伝ってもらうのは良いことです。これがIoCのコンセプトです。
MVCアーキテクチャーを備えた最新のWebアプリケーションは、URLルーティングを実行するためにフレームワークに依存し、フレームワークが呼び出すためにコントローラーを配置します。
依存性注入と制御の反転は関連しています。依存性注入はマイクロレベルであり、制御の反転はマクロレベルです。食事を終える(IoCを実装する)には、一口(DIを実装する)をすべて食べる必要があります。
Inversion of Controlを使用する前に、その長所と短所があることを十分に理解し、使用する場合はそれを使用する理由を知っておく必要があります。
長所:
短所:
個人的に私はIoCの強みを理解していますが、私はそれらが本当に好きですが、ソフトウェアを「実際の」プログラムではなく、以下でまとめる必要のあるクラスのコレクションに変えるため、可能な限りIoCを避ける傾向があります。 XML構成またはアノテーションのメタデータであり、それがないとバラバラになります(そしてバラバラになります)。
ウィキペディア記事。私にとって、制御の反転とは、順番に記述されたコードを委任構造に変えることです。プログラムはすべてを明示的に制御する代わりに、特定のことが発生したときに呼び出される特定の関数を備えたクラスまたはライブラリをセットアップします。
コードの重複を解決します。たとえば、昔は、手動で独自のイベントループを記述し、システムライブラリをポーリングして新しいイベントを探していました。現在、ほとんどの最新のAPIは、関心のあるイベントをシステムライブラリに通知するだけで、イベントが発生したときに通知されます。
制御の反転は、コードの重複を減らすための実用的な方法です。メソッド全体をコピーして、コードの小さな部分のみを変更する場合は、制御の反転を使って対処することを検討できます。制御の反転は、デリゲート、インターフェイス、または生の関数ポインターの概念を介して、多くの言語で簡単に行えます。
このように書くと、プログラムの流れをたどることが難しくなるため、すべての場合に使用することは適切ではありません。これは、再利用されるライブラリを作成するときにメソッドを設計するのに便利な方法ですが、コードの重複の問題を実際に解決しない限り、独自のプログラムのコアでは控えめに使用する必要があります。
しかし、あなたはそれに非常に注意する必要があると思います。このパターンを使いすぎると、デザインが非常に複雑になり、コードがさらに複雑になります。
このTextEditorの例のように:SpellCheckerが1つしかない場合、IoCを使用する必要は本当にないのでしょうか?単体テストなどを書く必要がない限り...
とにかく、合理的である。デザインパターンは良い習慣ですが、説教する聖書ではありません。どこにでも貼り付けないでください。
IoC / DIは、呼び出し元のオブジェクトへの依存関係を押し出しています。超シンプル。
非専門的な答えは、電源を入れる前に車のエンジンを交換できることです。すべてが正しく接続されていれば(インターフェース)、問題ありません。
制御の反転は、システムのコンポーネントとレイヤーを分離するために使用されるパターンです。パターンは、コンポーネントの構築時に依存関係をコンポーネントに注入することで実装されます。これらの依存関係は、通常、さらに分離し、テスト容易性をサポートするためのインターフェースとして提供されます。Castle Windsor、UnityなどのIoC / DIコンテナは、IoCの提供に使用できるツール(ライブラリ)です。これらのツールは、有効期間、AOP /インターセプト、ポリシーなどを含む、単純な依存関係の管理を超えた拡張機能を提供します。
a。コンポーネントの依存関係を管理する責任をコンポーネントから軽減します。
b。異なる環境で依存関係の実装を交換する機能を提供します。
c。依存関係のモックを通じてコンポーネントをテストできるようにします。
d。アプリケーション全体でリソースを共有するためのメカニズムを提供します。
a。テスト駆動開発を行う際に重要です。IoCがないと、テスト対象のコンポーネントがシステムの他の部分と高度に結合されているため、テストが困難になる可能性があります。
b。モジュール式システムを開発する際に重要です。モジュラーシステムは、再コンパイルせずにコンポーネントを交換できるシステムです。
c。特にエンタープライズアプリケーションで対処する必要のある分野横断的な懸念が多数ある場合は重要です。
最初の部分だけに答えます。それは何ですか?
制御の反転(IoC)は、最初にクラスのインスタンスを作成し、次にクラスインスタンスが依存関係のインスタンスを作成する代わりに、最初にクラスの依存関係のインスタンスを作成し、(オプションでコンストラクターを通じてそれらを注入する)ことを意味します。したがって、制御の反転は、プログラムの制御の流れを反転します。呼び出し先が制御のフローを制御する(依存関係を作成している間)の代わりに、呼び出し元がプログラムの制御のフローを制御します。
この2つの用語の簡単な理解を書き留めておきます。
For quick understanding just read examples*
依存関係の注入(DI):
依存関係の注入とは、通常、メソッドが依存オブジェクトを作成するのではなく、メソッドが依存するオブジェクトをパラメーターとしてメソッドに渡すことを意味します。
実際にそれが意味することは、メソッドが特定の実装に直接依存しないことです。要件を満たす任意の実装をパラメーターとして渡すことができます。
このオブジェクトを使用すると、依存関係がわかります。そして春はそれを利用可能にします。
これは、疎結合のアプリケーション開発につながります。
Quick Example:EMPLOYEE OBJECT WHEN CREATED,
IT WILL AUTOMATICALLY CREATE ADDRESS OBJECT
(if address is defines as dependency by Employee object)
制御の反転(IoC)コンテナー:
これはフレームワークの一般的な特性であり、IOC はインスタンス化からBeanFactoryによる破棄まで、Javaオブジェクトを管理
します。
-IoCコンテナーによってインスタンス化されるJavaコンポーネントはBeanと呼ばれ、IoCコンテナーは、Beanのスコープ、ライフサイクルイベント、およびそれが構成およびコーディングされているすべてのAOP機能を管理します。
QUICK EXAMPLE:Inversion of Control is about getting freedom, more flexibility, and less dependency. When you are using a desktop computer, you are slaved (or say, controlled). You have to sit before a screen and look at it. Using keyboard to type and using mouse to navigate. And a bad written software can slave you even more. If you replaced your desktop with a laptop, then you somewhat inverted control. You can easily take it and move around. So now you can control where you are with your computer, instead of computer controlling it
。
制御の反転を実装することにより、ソフトウェア/オブジェクトの消費者は、制御されたりオプションが少なくなったりする代わりに、ソフトウェア/オブジェクトに対してより多くの制御/オプションを取得します。
設計ガイドラインとしての制御の反転は、次の目的に役立ちます。
特定のタスクの実行と実装の分離があります。
すべてのモジュールは、その設計目的に焦点を合わせることができます。
モジュールは、他のシステムが何をするかについては何も想定していませんが、その契約に依存しています。
モジュールを交換しても他のモジュール
に影響はありません。ここでは抽象的なものにしておきます。トピックの詳細については、次のリンクにアクセスしてください。
例を上手に読む
たとえば、task#1はオブジェクトを作成することです。IOCの概念がなければ、タスク#1はプログラマーによって行われることになっていますが、IOCの概念では、タスク#1はコンテナーによって行われます。
簡単に言うと、コントロールはプログラマーからコンテナーに反転します。したがって、それは制御の反転と呼ばれます。
私たちはいくつかのホテルでいくつかの会議を行っているとしましょう。
多くの人、たくさんの水、たくさんのプラスチックカップ。
誰かが飲みたいとき、彼女はカップに水を入れ、飲み、床にカップを投げます。
時間か何かの後、私たちはプラスチックのカップと水で覆われた床を持っています。
制御を反転させます。
同じ場所での同じミーティングですが、プラスチック製のカップの代わりに、ガラスのカップが1つあるウェイターがあります(シングルトン)。
そして彼女はいつもゲストに飲酒を提供しています。
誰かが飲みたくなったら、彼女はウェイターグラスから飲み、それを飲んでウェイターに戻します。
衛生的で最後の形態の飲酒プロセス管理の問題は別として、はるかに効果的で経済的です。
そして、これはまさにSpring(たとえば、別のIoCコンテナ、Guice)が行うことです。アプリケーションに新しいキーワードを使用して必要なものを作成させるのではなく(プラスチックカップを取る)、Spring IoCコンテナーは常に、必要なオブジェクト(水のグラス)の同じインスタンス(シングルトン)をアプリケーションに提供します。
そのような会議の主催者として自分を考えてください。ホテル管理にメッセージを送る方法が必要です
会議のメンバーには、コップ1杯の水が必要ですが、ケーキは必要ありません。
例:-
public class MeetingMember {
private GlassOfWater glassOfWater;
...
public void setGlassOfWater(GlassOfWater glassOfWater){
this.glassOfWater = glassOfWater;
}
//your glassOfWater object initialized and ready to use...
//spring IoC called setGlassOfWater method itself in order to
//offer to meetingMember glassOfWater instance
}
便利なリンク:-
"IoC"の頭字語とその名前について最も混乱しているのは、名前があまりにも華やかで、ほとんどノイズの名前だということです。
手続き型プログラミングとイベント駆動型プログラミングの違いを説明する名前が本当に必要ですか?必要な場合はわかりましたが、解決する以上に混乱する、まったく新しい「人生よりも大きい」名前を選択する必要がありますか?
管理の逆転とは、食料品店に行き、妻が購入する製品のリストを提供するときです。
プログラミング用語では、彼女はgetProductList()
あなたが実行している関数にコールバック関数を渡しました- doShopping()
。
これにより、関数のユーザーが関数の一部を定義できるようになり、より柔軟になります。
getProductList()
お金の源を見つける必要があると言ったときから来ました、コントロールがあなたの側にあることを意味します。逆転の場合、彼女は支配します。つまり、彼女が購入するために提供するお金も意味します。
「コントロールが反転する」方法を説明する非常に明確な例をここで見つけました。
クラシックコード(Dependencyインジェクションなし)
DIを使用しないコードが大まかに機能する方法を次に示します。
依存性注入の使用
DIを使用したコードが大まかに機能する方法を次に示します。
依存関係の制御は、呼び出されているものから呼び出しているものに逆転します。
それはどのような問題を解決しますか?
依存性注入により、注入されたクラスのさまざまな実装と簡単に交換できます。単体テスト中にダミーの実装を挿入できるため、テストがはるかに簡単になります。
例:アプリケーションがユーザーがアップロードしたファイルをGoogleドライブに保存するとします。DIでは、コントローラーコードは次のようになります。
class SomeController
{
private $storage;
function __construct(StorageServiceInterface $storage)
{
$this->storage = $storage;
}
public function myFunction ()
{
return $this->storage->getFile($fileName);
}
}
class GoogleDriveService implements StorageServiceInterface
{
public function authenticate($user) {}
public function putFile($file) {}
public function getFile($file) {}
}
要件が変わると、GoogleDriveの代わりにDropboxを使用するよう求められます。StorageServiceInterfaceのドロップボックス実装を作成するだけで済みます。Dropboxの実装がStorageServiceInterfaceに準拠している限り、コントローラーに変更を加える必要はありません。
テスト中に、すべてのメソッドがnull(またはテスト要件に従って事前定義された値)を返すダミー実装を使用して、StorageServiceInterfaceのモックを作成できます。
代わりに、次のnew
ようなキーワードでストレージオブジェクトを構築するコントローラークラスがある場合:
class SomeController
{
private $storage;
function __construct()
{
$this->storage = new GoogleDriveService();
}
public function myFunction ()
{
return $this->storage->getFile($fileName);
}
}
Dropbox実装で変更するnew
場合は、GoogleDriveServiceオブジェクトが構築されているすべての行を置き換え、DropboxServiceを使用する必要があります。さらに、SomeControllerクラスをテストするとき、コンストラクターは常にGoogleDriveServiceクラスを予期し、このクラスの実際のメソッドがトリガーされます。
いつそれが適切でいつ適切でないのですか? 私の意見では、クラスの代替実装がある(またはある可能性がある)と考える場合、DIを使用します。
非常に簡単な書面による説明がここにあります
http://binstock.blogspot.in/2008/01/excellent-explanation-of-dependency.html
それは言う-
「重要なアプリケーションは、ビジネスロジックを実行するために相互に連携する2つ以上のクラスで構成されています。従来、各オブジェクトは、連携するオブジェクト(その依存関係)への独自の参照を取得する責任があります。DIを適用すると、オブジェクトには、システム内の各オブジェクトを調整する外部エンティティによって作成時に依存関係が与えられます。つまり、依存関係はオブジェクトに注入されます。」
制御の反転は一般的な原則ですが、依存性注入はオブジェクトグラフ構築の設計パターンとしてこの原則を実現します(つまり、構成は、オブジェクト自体が別のオブジェクトへの参照を取得する方法を制御するのではなく、オブジェクトが相互に参照する方法を制御します)。
制御の反転を設計パターンとして見ると、反転しているものを調べる必要があります。依存性注入は、オブジェクトのグラフを作成する制御を逆にします。素人の言葉で言うと、制御の逆転はプログラムの制御の流れの変化を意味します。例えば。従来のスタンドアロンアプリには、コントロールが他のサードパーティライブラリに渡されるメインメソッドがあります(ただし、サードパーティライブラリの関数を使用した場合)が、コントロールの反転により、コントロールがサードパーティライブラリコードからコードに転送されます、サードパーティライブラリのサービスを利用しているため。ただし、プログラム内で反転する必要がある他の側面があります。たとえば、コードを実行するためのメソッドとスレッドの呼び出しです。
Inversion of Controlの詳細に興味のある方のために、設計パターンとしてのInversion of Controlのより完全な図を概説する論文が公開されました(OfficeFloor:Officeパターンを使用してソフトウェア設計を改善するhttp://doi.acm.org/10.1145/ 2739011.2739013(http://www.officefloor.net/about.htmlからダウンロードできる無料のコピーを含む)。
識別されるのは次の関係です。
制御の反転(メソッドの場合)=依存関係(状態)注入+継続注入+スレッド注入
利用可能な制御の反転に関する上記の関係の概要 -http://dzone.com/articles/inversion-of-coupling-control
IoCは、コードとサードパーティコード(ライブラリ/フレームワーク)の関係を逆転させることです。
DI(Dependency Injection)は、アプリケーション内での制御の流れに関するものです。従来のデスクトップアプリケーションには、アプリケーション(main()メソッド)から他のライブラリメソッド呼び出しへの制御フローがありましたが、DI制御フローが逆になっているため、フレームワークがアプリの起動、初期化、必要に応じたメソッドの呼び出しを処理します。
最終的には常に勝つ:)
私はこの説明が好きです:http : //joelabrahamsson.com/inversion-of-control-an-introduction-with-examples-in-net/
シンプルに始まり、コード例も示しています。
消費者Xは、何かを実行するために消費クラスYを必要とします。それはすべて自然なことですが、XはYを使用していることを本当に知っている必要がありますか?
Xは、だれが実際に動作を実装しているのかを知らずに、Yの動作、メソッド、プロパティなどを持つものを使用していることをXが知っているだけでは十分ではないでしょうか。
以下のIに示すように、YでXが使用する動作の抽象的な定義を抽出し、コンシューマXがYの代わりにそのインスタンスを使用できるようにすることで、Yの詳細を知らなくても、引き続き機能を実行できます。
上の図では、YがIを実装し、XがIのインスタンスを使用しています。XがまだYを使用している可能性はかなりありますが、興味深いのは、Xがそれを知らないということです。Iを実装するものを使用していることを知っているだけです。
次のような利点の詳細と説明については、記事をご覧ください。
...
答えはすでにここに記載されていることを理解しています。しかし、私は今でも、コントロールの反転に関するいくつかの基本を、将来の読者のためにここで詳しく説明する必要があると思います。
Inversion of Control(IoC)は、Hollywood Principleと呼ばれる非常に単純な原理に基づいて構築されています。そしてそれは言う、
私たちに電話しないでください、私たちはあなたに電話します
それが意味することは、もしあなたに価値があるなら、ハリウッドがあなたを見つけてあなたの夢を実現させるよりもむしろあなたの夢を叶えるためにハリウッドに行くのではないということです。かなり反転しましたね?
IoCの原理について話し合うと、ハリウッドを忘れてしまいます。IoCには、ハリウッド、あなた、そして夢を実現するような3つの要素が必要です。
私たちのプログラミングの世界では、ハリウッドは一般的なフレームワーク(あなたや他の誰かが作成することもあります)を表し、あなたが書いたユーザーコードを表し、タスクはコードで達成したいことを表します。IoCではなく、自分でタスクをトリガーすることはありません。むしろ、フレームワークがタスクをトリガーするようにすべてを設計しました。したがって、誰かをヒーローにしたり、別のヒーローを悪役にしたりできる再利用可能なフレームワークを構築しました。しかし、そのフレームワークは常に担当しており、誰かをいつ選ぶかを知っており、誰かがそれが何になりたいかを知っているだけです。
ここでは実際の例を示します。Webアプリケーションを開発するとします。したがって、httpリクエストの処理、アプリケーションメニューの作成、ページの提供、Cookieの管理、イベントのトリガーなど、Webアプリケーションが処理する必要があるすべての一般的な処理を行うフレームワークを作成します。
さらに、フレームワークにいくつかのフックを残して、そこにさらにコードを追加してカスタムメニュー、ページ、Cookieを生成したり、ユーザーイベントをログに記録したりできます。すべてのブラウザーリクエストで、フレームワークが実行され、フックされた場合はカスタムコードが実行されて提供されます。ブラウザに。
したがって、アイデアは非常に単純です。すべてを制御するユーザーアプリケーションを作成するのではなく、まずすべてを制御する再利用可能なフレームワークを作成し、次にカスタムコードを記述してフレームワークにフックし、それらを適時に実行します。
LaravelとEJBはそのようなフレームワークの例です。
参照:
プログラミングスピーキング
簡単に言えば、IoCは、特定のクラス(フィールドやパラメーターなど)を、いくつかのクラスで使用できるワイルドカードとして特定する方法としてのインターフェースの使用です。コードの再利用を可能にします。
たとえば、2つのクラスDogとCatがあるとします。どちらも、年齢、サイズ、体重など、同じ品質/状態を共有しています。だから、代わりに呼ばれるサービスのクラス作成のDogServiceとCatServiceを、私はと呼ばれる単一のものを作成することができますAnimalService彼らはインターフェイスを使用する場合にのみ犬や猫を使用することができますIAnimalを。
しかし、実用的に言えば、それはいくつかの逆です。
a)ほとんどの開発者はそれを使用する方法を知りません。例えば、私はと呼ばれるクラスを作成することができますお客様をし、私が自動的に作成することができます(IDEのツールを使用して)と呼ばれるインターフェースICustomerを。したがって、インターフェイスが再利用されるかどうかに関係なく、クラスとインターフェイスで満たされたフォルダを見つけることは珍しくありません。それはBLOATEDと呼ばれています。一部の人々は、「将来的にはそれを使用できるようになるかもしれない」と主張することができます。:-|
b)いくつかの制限があります。たとえば、犬と猫の場合について話しましょう。犬専用の新しいサービス(機能)を追加したいと思います。犬を訓練する必要がある日数を計算したいとします(trainDays()
)。猫は役に立たないので、猫は訓練できません(冗談です)。
b.1)trainDays()
サービスAnimalServiceに追加すると、猫でも機能し、まったく無効になります。
b.2)trainDays()
使用するクラスを評価する条件を追加できます。しかし、それはIoCを完全に壊します。
b.3)新しい機能のためだけに、DogServiceという新しいサービスクラスを作成できます。しかし、Dogには2つのサービスクラス(同様の機能を持つ)があり、それが悪いため、コードの保守性が向上します。
私はこれについて多くの回答を読みましたが、誰かがまだ混乱していて、IoCを説明するためにさらに超「素人用語」が必要な場合は、ここに私の見解があります。
親子がお互いに話しているところを想像してみてください。
IoCなし:
*保護者:私が質問した場合にのみ発言でき、許可した場合にのみ行動できます。
保護者:これは、食べたり、遊んだり、トイレに行ったり、眠ったりすることができるかどうかを尋ねることができないことを意味します。
保護者:食べたいですか?
子供:いいえ。
保護者:よし、戻ってきます。私を待っててください。
子供:(遊びたいですが、親からの質問がないため、子供は何もできません)。
1時間後...
親:帰ってきた。あなたは遊びたいですか?
子供:はい。
保護者:許可が付与されました。
子:(最終的に遊ぶことができます)。
この簡単なシナリオは、コントロールが親を中心とすることを説明しています。子供の自由は制限されており、親の質問に大きく依存しています。子供は話すように求められたときにのみ話すことができ、許可が与えられたときにのみ行動することができます。
IoCの場合:
これで、子供は質問をすることができ、親は回答と許可で応答できます。単にコントロールが反転していることを意味します!現在、子供はいつでも自由に質問をすることができ、許可に関しては親との依存関係が依然としてありますが、彼は話したり質問したりする手段に依存していません。
技術的に説明すると、これはコンソール/シェル/ cmdとGUIの相互作用に非常に似ています。(これは、No.2のトップの回答を超えるMark Harrisonの回答です)。コンソールでは、何が要求/表示されているかに依存しているため、最初に質問に回答しないと他のメニューや機能にジャンプできません。厳密な順次フローに従います。(プログラム的には、これはメソッド/関数ループのようなものです)。ただし、GUIを使用すると、メニューと機能がレイアウトされ、ユーザーは必要なものをすべて選択できるため、より多くの制御が可能になり、制限が緩和されます。(プログラム的には、メニューを選択するとコールバックが発生し、アクションが実行されます)。
制御の反転とは、ライブラリからクライアントに制御を転送することです。ライブラリー関数の動作を制御(変更)する高次関数(ライブラリー関数)に関数値(ラムダ式)を挿入(渡す)するクライアントについて説明すると、より理にかなっています。(動作を実行する)ライブラリの依存関係をライブラリに挿入するクライアントまたはフレームワークもIoCと見なされる場合があります
質問にはすでに多くの回答がありますが、いずれも反転制御用語の内訳を示していませんので、より簡潔で有用な回答を提供する機会があると思います。
制御の反転は、依存関係反転原理(DIP)を実装するパターンです。DIPは次のように述べています。1.高レベルのモジュールが低レベルのモジュールに依存してはなりません。どちらも抽象化(インターフェースなど)に依存する必要があります。2.抽象化は詳細に依存すべきではありません。詳細(具体的な実装)は抽象化に依存する必要があります。
制御の反転には次の3つのタイプがあります。
インターフェース反転 プロバイダーはインターフェースを定義すべきではありません。代わりに、コンシューマーはインターフェースを定義し、プロバイダーはそれを実装する必要があります。インターフェイスの反転により、新しいプロバイダーが追加されるたびにコンシューマーを変更する必要がなくなります。
Flow Inversionフローの 制御を変更します。たとえば、多くのパラメータを入力するように要求したコンソールアプリケーションがあり、入力した各パラメータの後にEnterキーを押す必要があるとします。ここでフロー反転を適用して、ユーザーがパラメーターの入力シーケンスを選択でき、ユーザーがパラメーターを編集でき、最後の手順でユーザーがEnterキーを1回だけ押す必要があるデスクトップアプリケーションを実装できます。
作成の反転 これは、ファクトリパターン、サービスロケータ、および依存性注入のパターンで実装できます。作成の反転は、依存関係オブジェクトの作成プロセスを、これらの依存関係オブジェクトを使用するタイプの外に移動するタイプ間の依存関係を排除するのに役立ちます。依存関係が悪いのはなぜですか?以下にいくつかの例を示します。コードに新しいオブジェクトを直接作成すると、テストが難しくなります。再コンパイルせずにアセンブリの参照を変更することは不可能です(OCP原則違反)。デスクトップUIをWeb UIに簡単に置き換えることはできません。
メンテナンスはそれが私のために解決する一番のことです。2つのクラスが互いに親密にならないように、インターフェイスを使用していることが保証されます。
Castle Windsorのようなコンテナを使用すると、メンテナンスの問題がさらに解決されます。コード行を変更せずに、データベースに移動するコンポーネントをファイルベースの永続性を使用するコンポーネントに交換できることは素晴らしいです(構成を変更すれば完了です)。
そしてジェネリックに入ると、さらに良くなります。レコードを受信してメッセージを発行するメッセージ発行者がいると想像してください。何を公開するかは関係ありませんが、レコードからメッセージに何かを取り込むにはマッパーが必要です。
public class MessagePublisher<RECORD,MESSAGE>
{
public MessagePublisher(IMapper<RECORD,MESSAGE> mapper,IRemoteEndpoint endPointToSendTo)
{
//setup
}
}
一度書いたのですが、さまざまなタイプのメッセージを発行する場合は、このコードセットに多くのタイプを挿入できます。同じタイプのレコードを取り、それらを異なるメッセージにマップするマッパーを作成することもできます。GenericsでDIを使用すると、多くのタスクを実行するための非常に小さなコードを書くことができます。
そうそう、テスト容易性の問題がありますが、それらはIoC / DIの利点に次ぐものです。
私は間違いなくIoC / DIを愛しています。
3。やや複雑な中規模プロジェクトの場合は、より適切になります。痛みを感じ始めたらすぐに適切になると思います。