制御の反転とは何ですか?


1826

制御の反転(IoC)は、最初に遭遇したときに非常に混乱する可能性があります。

  1. それは何ですか?
  2. それはどの問題を解決しますか?
  3. いつ使用するのが適切で、いつ使用しないのですか?

292
これらの回答のほとんどの問題は、使用される用語です。コンテナとは?反転?依存?大きな言葉を使わずに平易な言葉で説明してください。
kirk.burleson


8
それは依存性注入(DI)です-マーティンファウラーの説明をここで参照してください:martinfowler.com/articles/injection.html#InversionOfControl
Ricardo Sanchez


それは形容詞であり、名詞ではなく、事物ではありません。これは、コードに加えられた変更の説明であり、フローの制御はデリゲートであり、コンテナではありません。
Martin Spamer

回答:


1523

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;
    }
}

最初のコード例では、インスタンス化SpellCheckerthis.checker = new SpellChecker();)しています。つまり、TextEditorクラスはクラスに直接依存していSpellCheckerます。

2番目のコード例では、コンストラクタのシグネチャにSpellChecker依存関係クラスを含めることで抽象化を作成してTextEditorいます(クラスの依存関係を初期化していません)。これにより、依存関係を呼び出して、次のようにTextEditorクラスに渡すことができます。

SpellChecker sc = new SpellChecker; // dependency
TextEditor textEditor = new TextEditor(sc);

これで、依存関係をシグネチャに挿入するため、TextEditorクラスを作成するクライアントSpellCheckerが使用する実装を制御できTextEditorます。


50
良い明確な例。ただし、ISpellCheckerインターフェイスをオブジェクトのコンストラクターに渡す必要はなく、設定可能なプロパティ(またはSetSpellCheckerメソッド)として公開したとします。これはまだIoCを構成しますか?
devios1 2008

25
chainguy1337-はい、そうです。このようなセッターの使用は、コンストラクター注入(どちらも依存性注入手法)ではなく、セッター注入と呼ばれます。IoCはかなり一般的なパターンですが、依存性注入はIoCを実現します
Jack Ukleja

257
多くの賛成投票にもかかわらず、この答えは正しくありません。martinfowler.com/articles/injection.html#InversionOfControlをご覧ください 。特に、「制御の逆転は用語が一般的すぎるため、人々は混乱を招きます。その結果、さまざまなIoC擁護者との多くの議論の結果、依存性インジェクションの名前を決めました」。
ホジェリオ

45
@Rogeriaに同意します。これはなぜそれがIoCと呼ばれるのかを説明していません。私は賛成票の数に驚いています;-)
Aravind Yarram

31
@Rogerioと@Pangeaに賛成です。これはコンストラクター注入の良い例かもしれませんが、元の質問に対する良い答えではありません。Fowlerで定義されているIoCは、サービスロケーターや単純な継承などを使用することで、いかなる種類のインジェクションも使用せずに実現できます。
mtsz

642

制御の反転は、たとえば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

したがって、制御が逆転します...コンピュータが固定された順序でユーザー入力を受け入れる代わりに、ユーザーはデータが入力される順序と、データがデータベースに保存されるタイミングを制御します。

基本的に、イベントループ、コールバック、または実行トリガーを持つものはすべてこのカテゴリに分類されます。


161
この男をマークダウンしないでください。技術的には彼は正しいmartinfowler.com/bliki/InversionOfControl.html IoCは非常に一般的な原則です。依存関係を外部システム(IoCコンテナーなど)に効果的に委任しているため、制御フローは依存関係の注入によって "反転"します
Jack Ukleja

38
シュナイダーのコメントに同意した。5反対票?これが本当に正しい唯一の答えなので、心は揺れ動きます。冒頭に注意してください:「GUIプログラムのように」。依存性注入は、IoCの最も一般的に見られる実現です。
ジェフスターナル

40
実際、これは数少ない正しいアンサーの1つです。皆さん、IoCは基本的に依存関係についてではありません。どういたしまして。
ホジェリオ

13
+1-これは、Martin Fowlerによる次のステートメントの(例を含む)良い説明です-"初期のユーザーインターフェイスは、アプリケーションプログラムによって制御されていました。" Enter name "、" enter address "のような一連のコマンドがあります。プログラムはプロンプトを駆動し、各プロンプトへの応答を取得します。グラフィカル(または画面ベースの)UIでは、UIフレームワークにこのメインループが含まれ、プログラムは代わりに画面上のさまざまなフィールドのイベントハンドラーを提供します。プログラムが逆転し、あなたから離れてフレームワークに移動しました。」
Ashish Gupta、

14
「ハリウッドの原則:私たちに電話しないでください、私たちはあなたに電話します」と時々面白く呼ばれる理由がわかります
Alexander Suraphel

419

制御の反転とは何ですか?

これらの簡単な2つの手順に従うと、制御の反転が完了します。

  1. 区切りから一部を-to-行う際に一部を-toが-行います。
  2. パーツがどのパーツについてほとんど知らない場合に確認します。およびその逆。

実装に使用しているテクノロジー/言語に基づいて、これらの各ステップで可能ないくつかの手法があります。

-

制御の反転(IoC)の反転部分は混乱を招くものです。なぜなら、反転は相対的な用語だからです。IoCを理解する最善の方法は、その単語を忘れることです。

-

  • イベント処理。イベントハンドラー(実行する部分)-イベントを発生させる(実行する部分)
  • インターフェース。コンポーネントクライアント(いつ実行するか)-コンポーネントインターフェイスの実装(実行する部分)
  • xUnitフィクスチャ。SetupとTearDown(実行する部分)-xUnitフレームワークは、最初にSetupを呼び出し、最後にTearDownを呼び出します(実行する部分)
  • テンプレートメソッドのデザインパターン。テンプレートメソッドwhen-to-doパート-プリミティブサブクラス実装what-to-doパート
  • COMのDLLコンテナーメソッド。DllMain、DllCanUnloadなど(実行する部分)-COM / OS(実行する部分)

インターフェースの言い方 インターフェース(例:依存性注入)を使用する場合、「いつ」としてのコンポーネントクライアント(いつ実行するか)は意味をなさないため、それを抽象化し、実装を追加する柔軟性をクライアントに提供しますが、「いつ」はありませんそこに関与。イベント処理のイベントを発生させる場合の「いつ」に同意します。
OldSchool

「コンポーネントクライアント」とは、インターフェイスのユーザー/クライアントを意味します。クライアントは、機能を拡張することを意図しているかどうかにかかわらず、「何をすべきか」の部分をトリガーする「タイミング」を知っています。
rpattabi

Martin Fowlerによるこの素晴らしい記事をご覧ください。彼は、インターフェースが制御の反転の基本部分をどのように作成するかを示しています。martinfowler.com
articles

最初の2つの文は見事です。驚くばかり !!いつやることと何をすべきかで完全に分離!! 他の回答がなぜ多くの賛成票を獲得するのか、私にはわかりません。彼らは理解せずにただコードを話します。
Amir Ziarati

2
私の説明のようにwhat-to-doしてwhen-to-do
KimchiMan

164

コントロールの反転は、懸念を分離することです。

IoCなしラップトップコンピューターを使用していて、誤って画面を壊してしまった そして、同じモデルのノートパソコンの画面が市場に出回っていないことがわかります。だからあなたは行き​​詰まっています。

IoCの場合デスクトップコンピューターがあり、誤って画面を壊してしまいます。市場に出ているほとんどすべてのデスクトップモニターを手に入れることができ、それはデスクトップでうまく動作します。

この場合、デスクトップはIoCを正常に実装します。さまざまなタイプのモニターを受け入れますが、ラップトップは受け入れませんが、修正するには特定の画面が必要です。


1
@Luo Jiong Hui素敵な説明。
Sachin

3
すべてではないにしても、ほとんどのデザインパターンには、日常生活に対応するものがあり、私たちがよく理解しています。設計パターンを理解する最も効率的な方法は、対応する日常生活を知ることです。そして私はたくさんあると信じています。
Luo Jiong Hui、2018

6
間違った答え。IoCではなく、依存関係の注入について説明しています。上記のこの回答
MickyD

2
同意する。これはDIであり、IoCではありません。シンプルなアプローチなので、まだ賛成票を獲得していますが、トピックの理解を深めるのに役立ちます。
2018

依存性注入について説明します。Iocではありません。しかし、素晴らしく明確な説明。
Chamin Wickramarathna

120

Inversion of Control(またはIoC)は自由を獲得することです(結婚し、自由を失い、あなたはコントロールされています。離婚し、あなたはInversion of Controlを実装しました。それが私たちが「分離」と呼んだものです。良いコンピューターシステム非常に近い関係はお勧めしません。)柔軟性の向上(オフィスのキッチンは、きれいな水道水のみを提供します。これは、飲みたいときに選択できる唯一の選択肢です。上司は、新しいコーヒーマシンをセットアップして、Inversion of Controlを実装しました。これで、水道水またはコーヒーを選択する柔軟性。)依存性が少ない (あなたのパートナーには仕事があります、あなたには仕事がなく、あなたは経済的にあなたのパートナーに依存しているので、あなたはコントロールされています。あなたは仕事を見つけ、あなたはコントロールの反転を実装しました。良いコンピューターシステムは独立を奨励します。)

デスクトップコンピューターを使用する場合、従属(つまり、制御)されています。あなたはスクリーンの前に座ってそれを見なければなりません。キーボードを使用して入力し、マウスを使用して移動します。そして、上手に書かれたソフトウェアはあなたをさらに奴隷にすることができます。デスクトップをラップトップに置き換えると、コントロールが多少逆になります。簡単に持ち運びできます。これで、コンピューターでコンピューターを制御する代わりに、コンピューターの現在の場所を制御できます。

制御の反転を実装することにより、ソフトウェア/オブジェクトコンシューマーは、制御されたりオプションが少なくなったりする代わりに、ソフトウェア/オブジェクトよりも多くの制御/オプションを取得します。

上記のアイデアを念頭に置いてください。まだIoCの重要な部分を見逃しています。IoCのシナリオでは、ソフトウェア/オブジェクトコンシューマーは洗練されたフレームワークです。つまり、作成したコードは自分では呼び出されません。次に、この方法がWebアプリケーションに適している理由を説明します。

コードがワーカーのグループであるとします。彼らは車を作る必要があります。これらの労働者には、車を組み立てるための場所とツール(ソフトウェアフレームワーク)が必要です。伝統的なソフトウェアフレームワークは、多くのツールとガレージのようになります。したがって、労働者は自分で計画を立て、ツールを使って車を組み立てる必要があります。車を作ることは簡単な仕事ではありません、労働者が適切に計画して協力することは本当に難しいでしょう。近代的ソフトウェアフレームワークは、すべての設備と管理者が配置された現代の自動車工場のようなものです。ワーカーは計画を立てる必要はありません。マネージャー(フレームワークの一部であり、彼らは最も賢い人々であり、最も洗練された計画を立てています)は、ワーカーがいつ仕事をするかを知るために調整を支援します(フレームワークはコードを呼び出します)。ワーカーは、マネージャーが(依存性注入を使用して)提供するツールを使用するのに十分な柔軟性が必要です。

ワーカーはトップレベルでプロジェクトを管理するコントロールをマネージャー(フレームワーク)に与えます。しかし、何人かの専門家に手伝ってもらうのは良いことです。これがIoCのコンセプトです。

MVCアーキテクチャーを備えた最新のWebアプリケーションは、URLルーティングを実行するためにフレームワークに依存し、フレームワークが呼び出すためにコントローラーを配置します。

依存性注入と制御の反転は関連しています。依存性注入はマイクロレベルであり、制御の反転はマクロレベルです。食事を終える(IoCを実装する)には、一口(DIを実装する)をすべて食べる必要があります。


21
DIを結婚と比較し、IoCを離婚と比較するために投票しました。
Marek Bar

「ワーカーはプロジェクトのトップレベルでの管理をフレームワーク(フレームワーク)に委ねていますが、専門家に手伝ってもらうのは良いことです。これはIoCの概念が真に由来しているものです。」-最初に制御はマネージャーと。そのコントロールがどのように反転するか説明できますか?専門家の助けを借りて(どのような専門家)?どうやって ?
Istiaque Ahmed

@Istiaque Ahmed、労働者がすべてを完全に制御できるガレージと比較すると、現代の自動車工場のマネージャーが生産を制御しています。したがって、今や労働者は管理する代わりに管理されています。この文脈でのマネージャーは労働者の一部ではなく、現代の自動車工場の一部であることに注意してください。専門家は、車の計画と製造を専門とするマネージャーです。
Luo Jiong Hui

2
既婚者へのメッセージ:離婚しないでください。子クラスもIoCを実装する場合があります。
ジュリアン

はい、これは結婚についての私のまさにビジョンですIoC
バロン

94

Inversion of Controlを使用する前に、その長所と短所があることを十分に理解し、使用する場合はそれを使用する理由を知っておく必要があります。

長所:

  • コードが分離されるため、インターフェースの実装を代替実装と簡単に交換できます
  • これは、実装ではなくインターフェースに対するコーディングの強力な動機です
  • コードの単体テストは、コンストラクター/セッターで受け入れるオブジェクトにのみ依存し、適切なオブジェクトを分離して簡単に初期化できるため、非常に簡単に記述できます。

短所:

  • IoCは、プログラムの制御フローを反転させるだけでなく、それをかなり曇らせます。つまり、通常はコード内に存在する接続がコード内に存在しないため、コードを読み取ってある場所から別の場所にジャンプすることができなくなります。代わりに、XML構成ファイルまたは注釈、およびこれらのメタデータを解釈するIoCコンテナーのコードにあります。
  • XML構成またはアノテーションが間違っているという新しいクラスのバグが発生し、特定の条件下でIoCコンテナーがオブジェクトの1つにnull参照を挿入する理由を見つけるのに多くの時間を費やすことができます。

個人的に私はIoCの強みを理解していますが、私はそれらが本当に好きですが、ソフトウェアを「実際の」プログラムではなく、以下でまとめる必要のあるクラスのコレクションに変えるため、可能な限りIoCを避ける傾向があります。 XML構成またはアノテーションのメタデータであり、それがないとバラバラになります(そしてバラバラになります)。


3
最初の詐欺は正しくありません。理想的には、コード内でIOCコンテナーを1回だけ使用する必要があり、それが主な方法です。それ以外はすべてそこからカスケードダウンする必要があります
mwjackson

23
IoCの場合、myServiceは単なるインターフェースであり、実際の実装はあなたが知らない限り、あなたが見ない限り、あなたはただ読むことができません:myService.DoSomething()とDoSomethingの定義に移動することはできませんxml構成ファイルまたはiocがセットアップされるメインメソッドでそれを設定します。
chrismay

7
それがResharperが役立つところです-インターフェースに対して「実装に移動」をクリックしてください。IoC(または具体的には例のDI)を回避することは、おそらく適切にテストしていないことも意味します
IThasTheAnswer

10
再:それはあなたのソフトウェアを、もはや「実際の」プログラムを構成しないクラスのコレクションに変えますが、XML構成または注釈メタデータによって組み立てる必要があり、それなしではバラバラになる(そして落ちる)ものだけです -私はこれを考えます非常に誤解を招きやすいです。同じことは、フレームワークの上に書かれたプログラムについても言えます。優れたIoCコンテナーとの違いは、プログラムが適切に設計および記述されている場合、それを取り出して、コードに最小限の変更を加えて別のコンテナーに展開するか、IoCを完全に破棄して、手動でオブジェクトを構築できることです。 。
Awnry Bear

7
このような実際の答えを見るのは良いことです!この「IoC」という流行語が発明される前に、インターフェース、ファクトリパターン、イベント駆動モデル、モッキングを適切に使用して、オブジェクト指向設計とTDDプラクティスに慣れている経験豊富なプログラマはたくさんいると思います。残念ながら、あまりにも多くの開発者/「アーキテクト」は、それらの優先フレームワークを使用しない場合、悪い習慣を主張します。私はより良い設計、組み込み言語の概念とツールの使用を好み、複雑さのほんの一部で同じ目標を達成します。つまり、あなたが言うように実装を「曇らせる」ことなく:-)
Tony Wall

68
  1. ウィキペディア記事。私にとって、制御の反転とは、順番に記述されたコードを委任構造に変えることです。プログラムはすべてを明示的に制御する代わりに、特定のことが発生したときに呼び出される特定の関数を備えたクラスまたはライブラリをセットアップします。

  2. コードの重複を解決します。たとえば、昔は、手動で独自のイベントループを記述し、システムライブラリをポーリングして新しいイベントを探していました。現在、ほとんどの最新のAPIは、関心のあるイベントをシステムライブラリに通知するだけで、イベントが発生したときに通知されます。

  3. 制御の反転は、コードの重複を減らすための実用的な方法です。メソッド全体をコピーして、コードの小さな部分のみを変更する場合は、制御の反転を使って対処することを検討できます。制御の反転は、デリゲート、インターフェイス、または生の関数ポインターの概念を介して、多くの言語で簡単に行えます。

    このように書くと、プログラムの流れをたどることが難しくなるため、すべての場合に使用することは適切ではありません。これは、再利用されるライブラリを作成するときにメソッドを設計するのに便利な方法ですが、コードの重複の問題を実際に解決しない限り、独自のプログラムのコアでは控えめに使用する必要があります。


37
ウィキペディアの記事は非常に混乱し、修正が必要だと思います。ディスカッションページで笑いをチェックしてください。
devios1 2008

独自のイベントループを作成しても、フレームワークの代わりにそのイベントループが使用され、残りのコードがIoCの原則を使用している場合は、独自のフレームワークを作成したばかりです。これは実際に悪いことではありません。コーディングを少し増やすだけで読みやすさが向上します(常に適切であるとは限りません)。
lijat

45

しかし、あなたはそれに非常に注意する必要があると思います。このパターンを使いすぎると、デザインが非常に複雑になり、コードがさらに複雑になります。

このTextEditorの例のように:SpellCheckerが1つしかない場合、IoCを使用する必要は本当にないのでしょうか?単体テストなどを書く必要がない限り...

とにかく、合理的である。デザインパターンは良い習慣ですが、説教する聖書ではありません。どこにでも貼り付けないでください。


3
スペルチェッカーが1つしかないことをどうやって知っていますか?
トレース

@Traceたとえば、作成するプログラムがどのように使用されるかを知ることができます。それでも、依存性注入などの一部の手法は非常に安価であるため、このような場合にそれらを使用しない理由はめったにありません。
lijat

44

IoC / DIは、呼び出し元のオブジェクトへの依存関係を押し出しています。超シンプル。

非専門的な答えは、電源を入れる前に車のエンジンを交換できることです。すべてが正しく接続されていれば(インターフェース)、問題ありません。


44

あなたがオブジェクトだとしましょう。そしてあなたはレストランに行きます:

IoCがない場合:「apple」を要求すると、さらに要求すると常にappleが提供されます。

IoCの場合:「フルーツ」を要求できます。あなたが提供されるたびに、さまざまな果物を得ることができます。たとえば、リンゴ、オレンジ、ウォーターメロンなどです。

そのため、明らかに、品種が好きな場合はIoCが推奨されます。


26
  1. 制御の反転は、システムのコンポーネントとレイヤーを分離するために使用されるパターンです。パターンは、コンポーネントの構築時に依存関係をコンポーネントに注入することで実装されます。これらの依存関係は、通常、さらに分離し、テスト容易性をサポートするためのインターフェースとして提供されます。Castle Windsor、UnityなどのIoC / DIコンテナは、IoCの提供に使用できるツール(ライブラリ)です。これらのツールは、有効期間、AOP /インターセプト、ポリシーなどを含む、単純な依存関係の管理を超えた拡張機能を提供します。

  2. a。コンポーネントの依存関係を管理する責任をコンポーネントから軽減します。
    b。異なる環境で依存関係の実装を交換する機能を提供します。
    c。依存関係のモックを通じてコン​​ポーネントをテストできるようにします。
    d。アプリケーション全体でリソースを共有するためのメカニズムを提供します。

  3. a。テスト駆動開発を行う際に重要です。IoCがないと、テスト対象のコンポーネントがシステムの他の部分と高度に結合されているため、テストが困難になる可能性があります。
    b。モジュール式システムを開発する際に重要です。モジュラーシステムは、再コンパイルせずにコンポーネントを交換できるシステムです。
    c。特にエンタープライズアプリケーションで対処する必要のある分野横断的な懸念が多数ある場合は重要です。


2
実際、IoCは主に依存関係の管理に関するものではありません。特にmartinfowler.com/articles/injection.html#InversionOfControlを参照してください。特に、「制御の反転は一般的すぎる用語なので、人々は混乱を招きます。その結果、さまざまなIoCの支持者との多くの議論の結果、 Dependency Injectionという名前で解決しました。
ホジェリオ

26

最初の部分だけに答えます。それは何ですか?

制御の反転(IoC)は、最初にクラスのインスタンスを作成し、次にクラスインスタンスが依存関係のインスタンスを作成する代わりに、最初にクラスの依存関係のインスタンスを作成し、(オプションでコンストラクターを通じてそれらを注入する)ことを意味します。したがって、制御の反転は、プログラムの制御流れを反転します。呼び出し先が制御フローを制御する(依存関係を作成している間)の代わりに呼び出し元がプログラムの制御のフローを制御します。


クラスやオブジェクトの作成に関するものではありません。こちらのmartinfowler.com/articles/injection.html#InversionOfControl
Raghvendra Singhを

22

この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

制御の反転を実装することにより、ソフトウェア/オブジェクトの消費者は、制御されたりオプションが少なくなったりする代わりに、ソフトウェア/オブジェクトに対してより多くの制御/オプションを取得します。

設計ガイドラインとしての制御の反転は、次の目的に役立ちます。

特定のタスクの実行と実装の分離があります。
すべてのモジュールは、その設計目的に焦点を合わせることができます。
モジュールは、他のシステムが何をするかについては何も想定していませんが、その契約に依存しています。
モジュールを交換しても他のモジュール
に影響はありません。ここでは抽象的なものにしておきます。トピックの詳細については、次のリンクにアクセスしてください。
例を上手に読む

詳細説明


17

NilObjectに同意しますが、これに追加したいと思います。

メソッド全体をコピーし、コードの小さな部分のみを変更する場合は、制御を逆にして対処することを検討できます。

コードをコピーして貼り付けている場合は、ほとんどの場合、何か間違ったことをしています。設計原則として1回限りのコード化。


17

たとえば、task#1はオブジェクトを作成することです。IOCの概念がなければ、タスク#1はプログラマーによって行われることになっていますが、IOCの概念では、タスク#1はコンテナーによって行われます。

簡単に言うと、コントロールはプログラマーからコンテナーに反転します。したがって、それは制御の反転と呼ばれます。

ここで良い例を見つけまし


コンテナはIoCの概念であり、依存関係(「ユーザー」オブジェクトと「使用済み」オブジェクトの関係)とオブジェクトインスタンスを含むオブジェクトモデルが存在し、管理されています(たとえば、含まれています)。コンテナーは通常、SpringなどのIoCフレームワークによって提供されます。これは、アプリケーションを構成するオブジェクトのランタイムリポジトリと考えてください。
Awnry Bear

17

私たちはいくつかのホテルでいくつかの会議を行っているとしましょう。

多くの人、たくさんの水、たくさんのプラスチックカップ。

誰かが飲みたいとき、彼女はカップに水を入れ、飲み、床にカップを投げます。

時間か何かの後、私たちはプラスチックのカップと水で覆われた床を持っています。

制御を反転させます。

同じ場所での同じミーティングですが、プラスチック製のカップの代わりに、ガラスのカップが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

}

便利なリンク:-


シングルトン静的型オブジェクトではありませんか?
Gokigooooks 2015年

16

"IoC"の頭字語とその名前について最も混乱しているのは、名前があまりにも華やかで、ほとんどノイズの名前だということです。

手続き型プログラミングとイベント駆動型プログラミングの違いを説明する名前が本当に必要ですか?必要な場合はわかりましたが、解決する以上に混乱する、まったく新しい「人生よりも大きい」名前を選択する必要がありますか?


1
IoC!=イベント駆動。類似点は(場合によっては重複しますが)、基本的に同じパラダイムではありません。
Awnry Bear

良い質問。イベント駆動型プログラミングは確かにIoCです。イベントハンドラを作成すると、イベントループから呼び出されます。ただし、IoCはイベントドリブンプログラミングよりも一般的な概念です。サブクラスでメソッドをオーバーライドする場合、IoCも一種のIoCです。適切な参照(インスタンス)が使用されたときに呼び出されるコードを記述します。
vi.su.

15

管理の逆転とは、食料品店に行き、妻が購入する製品のリストを提供するときです。

プログラミング用語では、彼女はgetProductList()あなたが実行している関数にコールバック関数を渡しました- doShopping()

これにより、関数のユーザーが関数の一部を定義できるようになり、より柔軟になります。


5
私の妻は通常私と一緒に買い物をしますが、私はこの声明に同意します。
ha9u63ar

1
@ ha9u63arあなたの妻はあなたと買い物をしますか?さて、それは集約と呼ばれています。
ジュリアン

2
彼女もお金を与える場合、それはDIと呼ばれます。
San

1
逆さま-逆さま-という言葉は、あなたの妻がgetProductList()お金の源を見つける必要があると言ったときから来ました、コントロールがあなたの側にあることを意味します。逆転の場合、彼女は支配します。つまり、彼女が購入するために提供するお金も意味します。
サン・

13

「コントロールが反転する」方法を説明する非常に明確な例をここで見つけました。

クラシックコード(Dependencyインジェクションなし)

DIを使用しないコードが大まかに機能する方法を次に示します。

  • アプリケーションにはFoo(コントローラーなど)が必要なので、次のようにします。
  • アプリケーションがFooを作成する
  • アプリケーションがFooを呼び出す
    • Fooにはバー(サービスなど)が必要なので、次のようにします。
    • フーはバーを作成します
    • フーはバーを呼ぶ
      • BarにはBim(サービス、リポジトリなど)が必要なので、次のようにします。
      • バーがビムを作成
      • バーは何かをします

依存性注入の使用

DIを使用したコードが大まかに機能する方法を次に示します。

  • アプリケーションにはFoo、Bar、Bimが必要なので、次のようにします。
  • アプリケーションがBimを作成する
  • アプリケーションはバーを作成し、それにBimを与えます
  • アプリケーションがFooを作成し、それにバーを与える
  • アプリケーションがFooを呼び出す
    • フーはバーを呼ぶ
      • バーは何かをします

依存関係の制御は、呼び出されているものから呼び出しているものに逆転します。

それはどのような問題を解決しますか?

依存性注入により、注入されたクラスのさまざまな実装と簡単に交換できます。単体テスト中にダミーの実装を挿入できるため、テストがはるかに簡単になります。

例:アプリケーションがユーザーがアップロードしたファイルを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を使用します。


「コントロール」がどのように反転するかを説明するのはこれだけなので、これが最も正しい答えになるはずです。
Yarimadam

これまでの最高の説明
Ali80

12

非常に簡単な書面による説明がここにあります

http://binstock.blogspot.in/2008/01/excellent-explanation-of-dependency.html

それは言う-

「重要なアプリケーションは、ビジネスロジックを実行するために相互に連携する2つ以上のクラスで構成されています。従来、各オブジェクトは、連携するオブジェクト(その依存関係)への独自の参照を取得する責任があります。DIを適用すると、オブジェクトには、システム内の各オブジェクトを調整する外部エンティティによって作成時に依存関係が与えられます。つまり、依存関係はオブジェクトに注入されます。」


12

制御の反転は一般的な原則ですが、依存性注入はオブジェクトグラフ構築の設計パターンとしてこの原則を実現します(つまり、構成は、オブジェクト自体が別のオブジェクトへの参照を取得する方法を制御するのではなく、オブジェクトが相互に参照する方法を制御します)。

制御の反転を設計パターンとして見ると、反転しているものを調べる必要があります。依存性注入は、オブジェクトのグラフを作成する制御を逆にします。素人の言葉で言うと、制御の逆転はプログラムの制御の流れの変化を意味します。例えば。従来のスタンドアロンアプリには、コントロールが他のサードパーティライブラリに渡されるメインメソッドがあります(ただし、サードパーティライブラリの関数を使用した場合)が、コントロールの反転により、コントロールがサードパーティライブラリコードからコードに転送されます、サードパーティライブラリのサービスを利用しているため。ただし、プログラム内で反転する必要がある他の側面があります。たとえば、コードを実行するためのメソッドとスレッドの呼び出しです。

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


これは非常に明確な答えです。説明ありがとう。
KunYu Tsai

11

IoCは、コードとサードパーティコード(ライブラリ/フレームワーク)の関係を逆転させることです。

  • 通常のソフトウェア開発では、main()メソッドを記述して「ライブラリ」メソッドを呼び出します。 あなたはコントロールしています:)
  • IoCでは、「フレームワーク」がmain()を制御し、メソッドを呼び出します。フレームワークは、コントロールである:(

DI(Dependency Injection)は、アプリケーション内での制御の流れに関するものです。従来のデスクトップアプリケーションには、アプリケーション(main()メソッド)から他のライブラリメソッド呼び出しへの制御フローがありましたが、DI制御フローが逆になっているため、フレームワークがアプリの起動、初期化、必要に応じたメソッドの呼び出しを処理します。

最終的には常に勝つ:)


10

私はこの説明が好きです: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を実装するものを使用していることを知っているだけです。

次のような利点の詳細と説明については、記事をご覧ください。

  • XはYに依存しなくなりました
  • より柔軟で、実行時に実装を決定できます
  • コードユニットの分離、簡単なテスト

...


リンクは非常に役立ちます。本当にありがとう:)
M FuatNUROĞLU19年

10

答えはすでにここに記載されていることを理解しています。しかし、私は今でも、コントロールの反転に関するいくつかの基本を、将来の読者のためにここで詳しく説明する必要があると思います。

Inversion of Control(IoC)は、Hollywood Principleと呼ばれる非常に単純な原理に基づいて構築されています。そしてそれは言う、

私たちに電話しないでください、私たちはあなたに電話します

それが意味することは、もしあなたに価値があるなら、ハリウッドがあなたを見つけてあなたの夢を実現させるよりもむしろあなたの夢を叶えるためにハリウッドに行くのではないということです。かなり反転しましたね?

IoCの原理について話し合うと、ハリウッドを忘れてしまいます。IoCには、ハリウッド、あなた、そして夢を実現するような3つの要素が必要です。

私たちのプログラミングの世界では、ハリウッドは一般的なフレームワーク(あなたや他の誰かが作成することもあります)表し、あなたが書いたユーザーコードを表し、タスクはコードで達成したいことを表します。IoCではなく、自分でタスクをトリガーすることはありません。むしろ、フレームワークがタスクをトリガーするようにすべてを設計しました。したがって、誰かをヒーローにしたり、別のヒーローを悪役にしたりできる再利用可能なフレームワークを構築しました。しかし、そのフレームワークは常に担当しており、誰かをいつ選ぶかを知っており、誰かがそれが何になりたいかを知っているだけです。

ここでは実際の例を示します。Webアプリケーションを開発するとします。したがって、httpリクエストの処理、アプリケーションメニューの作成、ページの提供、Cookieの管理、イベントのトリガーなど、Webアプリケーションが処理する必要があるすべての一般的な処理を行うフレームワークを作成します。

さらに、フレームワークにいくつかのフックを残して、そこにさらにコードを追加してカスタムメニュー、ページ、Cookieを生成したり、ユーザーイベントをログに記録したりできます。すべてのブラウザーリクエストで、フレームワークが実行され、フックされた場合はカスタムコードが実行されて提供されます。ブラウザに。

したがって、アイデアは非常に単純です。すべてを制御するユーザーアプリケーションを作成するのではなく、まずすべてを制御する再利用可能なフレームワークを作成し、次にカスタムコードを記述してフレームワークにフックし、それらを適時に実行します。

LaravelとEJBはそのようなフレームワークの例です。

参照:

https://martinfowler.com/bliki/InversionOfControl.html

https://en.wikipedia.org/wiki/Inversion_of_control


1
私がここで見つけた最も適切な答え。
ブルーレイ

8

プログラミングスピーキング

簡単に言えば、IoCは、特定のクラス(フィールドやパラメーターなど)を、いくつかのクラスで使用できるワイルドカードとして特定する方法としてのインターフェースの使用です。コードの再利用を可能にします。

たとえば、2つのクラスDogCatがあるとします。どちらも、年齢、サイズ、体重など、同じ品質/状態を共有しています。だから、代わりに呼ばれるサービスのクラス作成のDogServiceCatServiceを、私はと呼ばれる単一のものを作成することができますAnimalService彼らはインターフェイスを使用する場合にのみ犬や猫を使用することができますIAnimalを

しかし、実用的に言えば、それはいくつかの逆です。

a)ほとんどの開発者はそれを使用する方法を知りません。例えば、私はと呼ばれるクラスを作成することができますお客様をし、私が自動的に作成することができます(IDEのツールを使用して)と呼ばれるインターフェースICustomerを。したがって、インターフェイスが再利用されるかどうかに関係なく、クラスとインターフェイスで満たされたフォルダを見つけることは珍しくありません。それはBLOATEDと呼ばれています。一部の人々は、「将来的にはそれを使用できるようになるかもしれない」と主張することができます。:-|

b)いくつかの制限があります。たとえば、猫の場合について話しましょう。犬専用の新しいサービス(機能)を追加したいと思います。犬を訓練する必要がある日数を計算したいとします(trainDays())。猫は役に立たないので、猫は訓練できません(冗談です)。

b.1)trainDays()サービスAnimalServiceに追加すると、猫でも機能し、まったく無効になります。

b.2)trainDays()使用するクラスを評価する条件を追加できます。しかし、それはIoCを完全に壊します。

b.3)新しい機能のためだけに、DogServiceという新しいサービスクラスを作成できます。しかし、Dogには2つのサービスクラス(同様の機能を持つ)があり、それが悪いため、コードの保守性が向上します。


肥大化したクラス/インターフェースについて:すべてのインターフェースを常に再利用する必要はありません。大きなインターフェースを機能的な境界を確認するために多数の小さなインターフェースに分割することが理にかなっている場合があります。インターフェースが小さいほど、他の実装での再利用が容易になります。また、意味のある場所であればどこでもインターフェースにコーディングすることをお勧めします。「インターフェース分離」を検討してください。インターフェースを使用しているからといって、分離されているわけではありません。単一の太いインターフェースは役に立たない。-ちょうど私の2セント:)
MK

7

私はこれについて多くの回答を読みましたが、誰かがまだ混乱していて、IoCを説明するためにさらに超「素人用語」が必要な場合は、ここに私の見解があります。

親子がお互いに話しているところを想像してみてください。

IoCなし:

*保護者:私が質問した場合にのみ発言でき、許可した場合にのみ行動できます。

保護者:これは、食べたり、遊んだり、トイレに行ったり、眠ったりすることができるかどうかを尋ねることができないことを意味します。

保護者:食べたいですか?

子供:いいえ。

保護者:よし、戻ってきます。私を待っててください。

子供:(遊びたいですが、親からの質問がないため、子供は何もできません)。

1時間後...

:帰ってきた。あなたは遊びたいですか?

子供:はい。

保護者:許可が付与されました。

:(最終的に遊ぶことができます)。

この簡単なシナリオは、コントロールが親を中心とすることを説明しています。子供の自由は制限されており、親の質問に大きく依存しています。子供は話すように求められたときにのみ話すことができ、許可が与えられたときにのみ行動することができます。

IoCの場合:

これで、子供は質問をすることができ、親は回答と許可で応答できます。単にコントロールが反転していることを意味します!現在、子供はいつでも自由に質問をすることができ、許可に関しては親との依存関係が依然としてありますが、彼は話したり質問したりする手段に依存していません。

技術的に説明すると、これはコンソール/シェル/ cmdとGUIの相互作用に非常に似ています。(これは、No.2のトップの回答を超えるMark Harrisonの回答です)。コンソールでは、何が要求/表示されているかに依存しているため、最初に質問に回答しないと他のメニューや機能にジャンプできません。厳密な順次フローに従います。(プログラム的には、これはメソッド/関数ループのようなものです)。ただし、GUIを使用すると、メニューと機能がレイアウトされ、ユーザーは必要なものをすべて選択できるため、より多くの制御が可能になり、制限が緩和されます。(プログラム的には、メニューを選択するとコールバックが発生し、アクションが実行されます)。


6

制御の反転とは、ライブラリからクライアントに制御を転送することです。ライブラリー関数の動作を制御(変更)する高次関数(ライブラリー関数)に関数値(ラムダ式)を挿入(渡す)するクライアントについて説明すると、より理にかなっています。(動作を実行する)ライブラリの依存関係をライブラリに挿入するクライアントまたはフレームワークもIoCと見なされる場合があります


5

質問にはすでに多くの回答がありますが、いずれも反転制御用語の内訳を示していませんので、より簡潔で有用な回答を提供する機会があると思います。

制御の反転は、依存関係反転原理(DIP)を実装するパターンです。DIPは次のよ​​うに述べています。1.高レベルのモジュールが低レベルのモジュールに依存してはなりません。どちらも抽象化(インターフェースなど)に依存する必要があります。2.抽象化は詳細に依存すべきではありません。詳細(具体的な実装)は抽象化に依存する必要があります。

制御の反転には次の3つのタイプがあります。

インターフェース反転 プロバイダーはインターフェースを定義すべきではありません。代わりに、コンシューマーはインターフェースを定義し、プロバイダーはそれを実装する必要があります。インターフェイスの反転により、新しいプロバイダーが追加されるたびにコンシューマーを変更する必要がなくなります。

Flow Inversionフローの 制御を変更します。たとえば、多くのパラメータを入力するように要求したコンソールアプリケーションがあり、入力した各パラメータの後にEnterキーを押す必要があるとします。ここでフロー反転を適用して、ユーザーがパラメーターの入力シーケンスを選択でき、ユーザーがパラメーターを編集でき、最後の手順でユーザーがEnterキーを1回だけ押す必要があるデスクトップアプリケーションを実装できます。

作成の反転 これは、ファクトリパターン、サービスロケータ、および依存性注入のパターンで実装できます。作成の反転は、依存関係オブジェクトの作成プロセスを、これらの依存関係オブジェクトを使用するタイプの外に移動するタイプ間の依存関係を排除するのに役立ちます。依存関係が悪いのはなぜですか?以下にいくつかの例を示します。コードに新しいオブジェクトを直接作成すると、テストが難しくなります。再コンパイルせずにアセンブリの参照を変更することは不可能です(OCP原則違反)。デスクトップUIをWeb UIに簡単に置き換えることはできません。


3
  1. 上記の 1番です制御の反転とは何ですか?

  2. メンテナンスはそれが私のために解決する一番のことです。2つのクラスが互いに親密にならないように、インターフェイスを使用していることが保証されます。

Castle Windsorのようなコンテナを使用すると、メンテナンスの問題がさらに解決されます。コード行を変更せずに、データベースに移動するコンポーネントをファイルベースの永続性を使用するコンポーネントに交換できることは素晴らしいです(構成を変更すれば完了です)。

そしてジェネリックに入ると、さらに良くなります。レコードを受信して​​メッセージを発行するメッセージ発行者がいると想像してください。何を公開するかは関係ありませんが、レコードからメッセージに何かを取り込むにはマッパーが必要です。

public class MessagePublisher<RECORD,MESSAGE>
{
    public MessagePublisher(IMapper<RECORD,MESSAGE> mapper,IRemoteEndpoint endPointToSendTo)
    {
      //setup
    }
}

一度書いたのですが、さまざまなタイプのメッセージを発行する場合は、このコードセットに多くのタイプを挿入できます。同じタイプのレコードを取り、それらを異なるメッセージにマップするマッパーを作成することもできます。GenericsでDIを使用すると、多くのタスクを実行するための非常に小さなコードを書くことができます。

そうそう、テスト容易性の問題がありますが、それらはIoC / DIの利点に次ぐものです。

私は間違いなくIoC / DIを愛しています。

3。やや複雑な中規模プロジェクトの場合は、より適切になります。痛みを感じ始めたらすぐに適切になると思います。



3

クラス内でオブジェクトを作成することは密結合と呼ばれ、Springは設計パターン(DI / IOC)に従ってこの依存関係を削除します。クラス内のどのオブジェクトが、クラス内で作成するのではなく、コンストラクター内で渡されるか。さらに、コンストラクターでスーパークラス参照変数を指定して、より一般的な構造を定義します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.