Inversion of Controlの名前がそのようになっているのはなぜですか?


98

単語invertor controlは、私が見た定義で制御の反転を定義するためにまったく使用されていません。

定義

ウィキペディア

制御の反転(IoC)は、オブジェクト指向プログラミングの観点からここで表現されるプログラミング手法です。オブジェクト結合は、実行時にアセンブラオブジェクトによってバインドされ、通常、静的解析を使用したコンパイル時には不明です。〜http://en.wikipedia.org/wiki/Inversion_of_control

マーティン・ファウラー

Inversion of Controlは、Javaコミュニティの一般的なパターンであり、軽量コンテナをワイヤリングしたり、さまざまなプロジェクトのコンポーネントを凝集したアプリケーションに組み立てたりするのに役立ちます。〜に基づいて http://www.martinfowler.com/articles/injection.html (言い換え)


それでは、Inversion of ControlがInversion of Controlと呼ばれるのはなぜですか?どのような制御が逆にされており、何によって?反転制御という用語を使用して、制御の反転を定義する方法はありますか?


22
これをわかりやすい英語で
ロバートハーベイ

2
定義が定義している単語を使用した場合、それは辞書の失敗になります。ここでも同様のロジックが適用されます。
イズカタ


2
@Izkata、辞書では、フレーズ自体の用語または同義語でフレーズを定義することが非常に一般的です。すなわち、自然の力の定義は、その定義で力と自然という言葉を使用するか、サービス定義の用語は、ルールと用語が同義語であるルールとサービスという用語を使用します。
コレイヒントン

3
この理由から、IoCの代わりに「自動化された依存性注入」またはADIという用語を使用することを好みます。ファウラー自身は、プログラミングにおける現在のほとんどのパラダイムには、ある種の「制御の反転」があり、その用語は一般に「実行されるコードの決定と外部に実行されるべき時間の解放」と定義されていると述べています。そのような決定が伝統的にプログラム自体によって行われる場合の制御システム」。ハードウェア割り込みからイベント駆動型プログラミング、仮想マシン、マルチタスクまで、すべてがIoCで発生します。
キース

回答:


67

ある種の「リポジトリ」クラスがあり、そのリポジトリがデータソースからあなたにデータを渡す責任があるとしましょう。

リポジトリは、それ自体でデータソースへの接続を確立できます。しかし、リポジトリのコンストラクタを介してデータソースへの接続を渡すことができたらどうでしょうか?

呼び出し元が接続を提供できるようにすることで、データソース接続の依存関係をリポジトリクラスから切り離し、リポジトリが指定するデータソースだけでなく、すべてのデータソースがリポジトリを操作できるようにしました。

リポジトリクラスから呼び出し元への接続を作成する責任を委任することにより、制御反転しました。

Martin Fowlerは、「依存性注入」という用語を使用してこのタイプの制御の反転を説明することを提案しています。


3
これは依存性注入の例ですが、依存性注入は制御の反転のサブセットにすぎません。制御の反転を実行する依存性注入とはまったく関係のないものが他にもあります。
dsw88

1
@ mustang2009cobra:ありがとう。例は、私が望んでいたことであり、それが発生するインスタンスの包括的なカタログではありません。「制御の反転」という用語は、メッセージパッシングやその他の同様の概念ではなく、DIと最も密接に関連付けられています。
ロバートハーベイ

確かに、依存性注入はIoCの最も一般的な例であるため、DIの例が最も理にかなっています。おそらく、これがDIの例であり、IoCの最も顕著なタイプであることを指定する回答への小さな変更でしょうか?
dsw88

1
これはまさに私が探していたものです!IoCの例と定義の多くは、どのコントロールが反転されるかを明確に指定していません。IoCには、単なる依存関係の注入以上のものがあることを認識していますが、今ではようやく何かが私の脳内でクリックされました。ありがとう!
コレイヒントン

79

あなたがリンクた記事をさらに下にマーティン・ファウラーよりも誰もそれをうまく説明できないと思います。

この新しい種類のコンテナでは、反転はプラグインの実装をルックアップする方法に関するものです。私の素朴な例では、リスターはファインダーの実装を直接インスタンス化して検索しました。これにより、ファインダーがプラグインになりません。これらのコンテナが使用するアプローチは、プラグインのすべてのユーザーが、個別のアセンブラモジュールがリスタに実装を注入できるようにする何らかの規則に従うようにすることです。

上記の段落で彼が説明しているように、これは「制御の反転」という用語が生まれた理由とまったく同じではありません。

これらのコンテナが「制御の反転」を実装しているので、それらがどのように役立つかについて話すとき、私は非常に困惑します。制御の反転はフレームワークの共通の特性であるため、制御の反転を使用するためこれらの軽量コンテナーは特別であると言うことは、車輪が付いているために私の車が特別であると言うようなものです。

問題は、制御のどの側面が反転しているのかということです。最初に制御の反転に遭遇したとき、それはユーザーインターフェイスのメイン制御にありました。初期のユーザーインターフェイスは、アプリケーションプログラムによって制御されていました。「名前を入力」、「アドレスを入力」などの一連のコマンドがあります。プログラムがプロンプトを駆動し、各プロンプトに対する応答を取得します。グラフィカル(または画面ベース)UIでは、UIフレームワークにこのメインループが含まれ、プログラムは画面上のさまざまなフィールドのイベントハンドラーを代わりに提供します。プログラムの主な制御は逆になり、あなたから離れてフレームワークに移動しました。

Inversion of Controlのこの特定の実装をカバーするために、彼が「依存性注入」という用語を作り続けたのはそのためです。

その結果、このパターンにはより具体的な名前が必要だと思います。制御の反転はあまりにも一般的な用語であるため、人々はそれを混乱させています。さまざまなIoC支持者との多くの議論の結果、Dependency Injectionという名前に決めました。

少し明確にするために:Inversion of Controlとは、プログラムの制御構造を古典的な手続き型設計から反転させるものを意味します。

昔のこの重要な例は、UIを直接生成するためにコードを残すのではなく、フレームワークにUIとコード間の通信を処理させることでした。

より最近の時代(このようなフレームワークがほとんど支配的だったため、問題はもはや関連しなくなっていた)、例はオブジェクトのインスタンス化に対する制御を反転させることでした。

ファウラーなどは、Inversion of Controlという用語があまりにも多くのテクニックをカバーしていると判断し、オブジェクトのインスタンス化の特定の例(Dependency Injection)に新しい用語が必要でしたが、合意が成立するまでに、「IoC Container 「離陸した。

IoCコンテナは特定の種類の依存性注入ですが、依存性注入は特定の種類のInversion of Controlであるため、これにより水がかなり濁ります。これが、あなたがどこを見ても、そのような混乱した答えを得ている理由です。


4
私は通常あまり投票しませんが、これは素晴らしい答えです。1票では不十分です。:(
RJD22

1
この答えは、IoCとDIの混乱のすべての質問に本当に答えています。
アリUmair

32

以下は、通常続く「通常の」制御フロープログラムです。

  • コマンドを順番に実行する
  • プログラムの制御フローに対する制御を維持します

制御の反転は、その制御フローを「反転」します。つまり、頭の上で反転します。

  • あなたのプログラムはもうフローを制御しません。適切と思われるコマンドを呼び出すのではなく、他の誰かがあなたを呼び出すのを待ちます

その最後の行は重要なものです。気分がいいときに誰かに電話するのではなく、気分がいいときに誰かに電話をかけます。

これの一般的な例は、RailsなどのWebフレームワークです。コントローラを定義しますが、実際にそれらが呼び出されるかどうかは決定しません。Railsは、必要があると判断したときにそれらを呼び出します。


19
[ここに必須の「ソビエトで」ジョークを挿入]
ロバートハーヴェイ

2
冗談はさておき、あなたが説明しているのはメッセージパッシングに似ていると思います。これは何十年もオブジェクト指向の定番でした。
ロバートハーベイ

3
@JimmyHoffa-これはまったく間違っていません-こちらをご覧ください。制御の反転は、依存関係の作成よりも一般的な概念であり、依存関係の注入はIoCの1つの形式にすぎません。
リー

7
@JimmyHoffa:私は同意しません。これは、あなたの答えやロバートのものと同じくらい、コントロールの反転の正しい定義です。
pdr

5
@pdrのこの声明に同意します。「制御の反転とは、プログラムの制御構造を従来の手続き型設計から反転させるものを意味します。」それが私が説明していることであり、それはコントロールの一般的な反転です。依存性注入は、IoCのタイプであるが、それはのIoCを実践唯一のものではありません
dsw88

13

依存関係のインスタンス化を制御するのは誰ですか。

従来、クラス/メソッドが別のクラス(依存関係)を使用する必要がある場合、クラス/メソッドによって直接インスタンス化されます。依存関係を制御します。

Inversion of Control(IoC)を使用すると、呼び出し元は依存関係を渡したため、依存関係をインスタンス化します。呼び出し元は依存関係を制御します。

依存関係がインスタンス化される場所の制御が逆になりました-必要なコードがある「ボトム」ではなく、必要なコードが呼び出される「トップ」でインスタンス化されます。


1
わかりやすい英語ではありません。不合格。
ロバートハーベイ

2
@RobertHarvey-平野はどれほど平野ですか?
オデッド

4
@RobertHarveyえ?これは私にはかなり明白に思えます...明白でないものは何ですか?「インスタンス化」または「依存関係」という言葉は?
ジミー・ホッファ

@JimmyHoffa:具体的な例を提供する私の答えをご覧ください。IoCは、誰もが使用しているが説明はしていない厄介な用語の1つです。人々は誤解しているため、IoCコンテナーを必要としないプログラムで使用しています。とはいえ、この答えには忍者の編集がいくつかあったと思います。:)
ロバートハーベイ

これと上記の@ dsw88の投稿は、私にとって非常に明白です。IoCについて聞いたことがないなら、直観的に「ああ、だれが何かをコントロールできるようになるかは、一方から他方へと反転する」と思います。これで良い仕事です!
オリバーウィリアムズ

2

通常、高レベルのコード呼び出し(つまり、コントロール)は低レベルのコードです。Main()はfunction()を呼び出し、function()はlibraryFunction()を呼び出します。

これは逆にすることができるため、下部の低レベルライブラリ関数は高レベル関数を呼び出します。

どうしてそうするか?ミドルウェア。トップレベルとボトムレベルを制御したい場合もありますが、途中でやりたくないことがたくさんあります。C stdlibでクイックソートの実装を行います。トップレベルでクイックソートを呼び出します。qsort()には、自分の好きなものにコンパレータを実装する独自の関数への関数ポインタを渡します。qsort()が呼び出されると、このコンパレータ関数が呼び出されます。qsort()は、高レベル関数を制御/呼び出し/駆動しています。


1

以下に簡単な概要を示します。

  1. 制御とは、プログラムが次に行うことを指します
  2. 最上位レベルには、通常、コントロールを制御する2つのものがあります。アプリケーション自体とユーザーです。

昔は、コントロールは最初にアプリケーションによって、次にユーザーによって所有されていました。アプリケーションがユーザーから何かを必要とする場合、アプリケーションは停止して尋ね、次のタスクに進みます。ユーザーの対話は、アプリケーションが次に行うことを制御するのではなく、ほとんどデータを提供しました。この種の動作はあまり頻繁に見られないため、これは最近私たちにとって少し異質です。

それを切り替えて、ユーザーにプライマリコントロールを与えると、コントロールが反転します。これは、ユーザーがアプリケーションが何かをするのを待つ代わりに、アプリケーションがユーザーが何かをするのを待つのを待つことを意味します。GUIはこれの優れた例であり、イベントループを備えたほとんどすべてのものが制御を反転させます。

私の例は最上位にあり、この制御の反転の概念は、アプリケーション内の異なる制御層に抽象化できることに注意してください(つまり、依存性注入)。これが、まっすぐな答えを得るのがとても難しい理由かもしれません。


0

2つの例を通してそれを理解してみましょう。

例1

以前のアプリは、コマンドプロンプトを生成して、ユーザー入力を次々に受け入れていました。現在、UIフレームワークはさまざまなUI要素をインスタンス化し、それらのUI要素のさまざまなイベント(マウスホバー、クリックなど)をループし、ユーザー/メインプログラムはそれらのイベントをリッスンするためのフック(JavaのUIイベントリスナーなど)を提供します。そのため、メインUI要素フローの「コントロール」は、ユーザープログラムからUIフレームワークに移動します。以前は、ユーザープログラムにありました。

例2

CustomerProcessor以下のクラスを検討してください。

class CustomerProcessor
{
    SqlCustRepo custRepo = new SqlCustRepo(); 
    private void processCustomers()
    {
            Customers[] custs = custRepo.getAllCusts();
    }
}

私がしたい場合processCustomer()のいずれかの実装に依存しないようにgetAllCusts()が提供するものだけではなく、SqlCustRepo私はラインを取り除く必要がありますSqlCustRepo custRepo = new SqlCustRepo()し、そのような実装のさまざまな種類を受け入れることができる、より汎用的なもの、と交換processCustomers()するだけのために動作します提供された実装。上記のコード(SqlCustRepoメインプログラムロジックによる必要なクラスのインスタンス化)は従来の方法でありprocessCustomers()、の実装から切り離すというこの目標を達成しませんgetAllCusts()。制御の反転では、コンテナは必要な実装クラスをインスタンス化し(xml設定などで指定)、メインプログラムロジックに挿入し、指定されたフックごとにバインドします(たとえば、スプリングフレームワークの@Autowiredアノテーションまたは getBean()メソッドによって)。

これがどのように行われるかを見てみましょう。以下のコードを検討してください。

Config.xml

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
    <bean id="custRepo" class="JsonCustRepo" />
</beans>

CustRepo.java

interface ICustRepo 
{ ... }

JsonCustRepo.java

class JsonCustRepo implements CustRepo
{ ... }

App.java

class App
{
    public static void main(String[] args) 
    {
        ApplicationContext context = new ClassPathXmlApplicationContext("Config.xml");
        ICustRepo custRepo = (JsonCustRepo) context.getBean("custRepo");
    }
}

私たちも持つことができます

class GraphCustRepo implements ICustRepo { ... }   

そして

<bean id="custRepo" class="GraphCustRepo">

App.javaを変更する必要はありません。

コンテナ(Springフレームワーク)の上には、xmlファイルをスキャンし、特定のタイプのBeanをインスタンス化し、それをユーザープログラムに挿入する責任があります。ユーザープログラムは、どのクラスをインスタンス化するかを制御できません。

PS:IoCは一般的な概念であり、多くの方法で達成されます。上記の例は、依存性注入によって実現しています。

参照: Martin Fowlerの記事

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