インジェクション制御の依存関係の反転

画像



エントリー



確かに、見出しを見たときに最初に発生した質問は「 Shta?でした 。 実際、Google翻訳の「 制御の反転、依存関係の注入 」というフレーズを中国語に翻訳してから、元に戻しました。 なんで? それから、私の意見では、これは実際に起こっていることの良い例です。 周りの人々は、これらの概念を混乱歪曲歪曲しています。 勤務中、私は多くのインタビューを行っていますが、DIについて質問するときに聞くことの90%は、率直に言って、率直なナンセンスです。 Habrで検索したところ、このトピックを開こうとするいくつかの記事が見つかりましたが、私はそれらが非常に好きだったとは言えません(大丈夫、大丈夫、ちょうど最初の3ページを見て、悔い改めました)。 ここで、Habrで、 Injection of ContainerなどのIoC復号化のコメントで会いました。 誰かが真剣に、DIの近くのどこかに共存する何らかの種類のコンテナ注入メカニズムがあり、明らかに同様のことを行うことさえあると示唆しています。 コンテナのみ。 うーん 実際、依存関係の実装を理解するのは非常に簡単です。必要なことは...



驚くべきことに、事実は、この「ちょうど...」で実際に動作するということです! さもなければ、あなたはここにいないでしょうか?



リチャード・ファインマンは、非常に複雑なことを明確かつ簡単に説明できる素晴らしいストーリーテラーでした(少なくとも、このビデオを参照)。 Joel Spolskyは、真に賢いプログラマーは(Cだけでなく)人間の言語でコミュニケーションできなければならないと考えています。 おそらく、ほとんどの人がアルバートアインシュタインの格言を知っています 。「 6歳の子供に何かを説明できないなら、あなた自身はこれを理解していません 。」 もちろん、6歳児と比較するつもりはありませんが、それでもDI、IoC、および他のDIについて、できるだけシンプルで明快に話そうとします。



NBコンストラクターセッターを介した依存性注入に加えて、 インターフェイスを介した3番目の方法の実装もあることをご存知ですか? これはこの記事の範囲を超えていますが、あなたは今あなた自身のために何か新しいものを発見したか、少なくとも収穫済みの腐ったトマトを落としたに違いありません。



制御の反転



休日は何をしていますか? 本を読むかもしれません。 たぶん、あなたはビデオゲームをします。 コードを書くか、次のシリーズを見てビールを飲むかもしれません(火星にリンゴの木を植える代わりに)。 しかし、あなたが何をしても、一日は完全に自由であり、あなただけがそのスケジュールを制御します。



ただし、残念なことに、週末が終わり、月曜日が来て、あなたは仕事に行かなければなりません(もちろん、あなたが持っている場合を除きます)。 雇用契約の条件では、午前8時に自宅にいなければなりません。 正午まで働きます。 その後、昼休みをとり、さらに4時間の活発な活動を行います。 最後に、午後5時にオフィスを出て家に帰ると、再びリラックスしてピヴァンドリアに乗ることができます。 違いを感じますか? あなたもはやあなたの毎日のスケジュールを管理 するのでなく 、それは他の誰か -あなたの雇用主によって行われます。



別の例を考えてみましょう。 テキストインターフェースを備えたアプリケーションを書いているとしましょう。 Main関数では、ユーザー入力を要求し、ユーザーに一連の文字を要求し、受信したデータを処理するルーチンを呼び出して(個別のストリームでも)、接続されたライブラリから一般的な関数を要求します。 したがって、すべての力があなたの手に集中し、あなたが書くコードアプリケーションのフローを完全に制御します。



しかし、ある晴れた日、上司がオフィスに入り、最も不快なニュースを報告します。コンソールはもはや流行ではなく、世界はグラフィカルインターフェイスによって支配されています。つまり、すべてをやり直す必要があります。 モダンで柔軟な(ヨガのクラスだけでなく)プログラマであるため、すぐに変更を加えることができます。 これを行うには、GUIフレームワークを接続し、イベント処理コードを記述します。 このボタンが押された場合、それを行う必要があります。 また、ユーザーがドロップダウンリストで選択を変更した場合、これとこれを省くことができません。 すべて順調に進んでいますが、ここでは、それが何らかの形で異なっていたことを理解しています。 実際、誰があなたがそんなに一生懸命プログラムしているこれらのイベントハンドラを呼び出すのでしょうか? ユーザーがクリックした場所とタイミングは誰が決定しますか? 何が起こっているの? 私の靴下はどこですか? GUIフレームワークは、あなたが思っていたよりも明らかにトリッキーであることが判明しアプリケーションフロー制御しました



これは、制御の反転です。これは、実行スレッドを外部のエンティティに設定するという事実を前提とする非常に抽象的な原理です。



IoCの概念は、 フレームワークの概念と密接に関連しています。 これは、再利用可能なコードを設計する別の方法-関数をプログラムから単に呼び出すライブラリーと区別する主な特性です。 フレームワークは、事前定義された拡張ポイントを提供する外部フレームワークです。 これらの拡張ポイントにコードを挿入しますが、呼び出されたときにそれを定義するのはフレームワークです。



宿題として、 Jeff SutherlandがSCRUMは方法論ではなくフレームワークであると主張する理由を検討してください。



依存関係の反転



これは、略語「 SOLID」の同じ文字Dです。





少しわかりにくい表現なので、次の例を考えてください(例としてC#を使用します)。



public class Foo { private Bar itsBar; public Foo() { itsBar = new Bar(); } }
      
      





ここでの問題は、Fooクラスが特定のBarクラスに依存することです。 何らかの理由で-それのために拡張可能、再利用可能、またはテスト可能にするために-それらを分離するタスクが発生する場合があります。 依存関係の逆転の原則によれば、それらの間に中間の抽象化を導入する必要があります。



 public class Foo { private IBar itsBar; public Foo() { itsBar = new Bar(); } }
      
      





UML図は、両方のオプションを示しています。



画像






あなたが尋ねると困難が始まりますが、ここでの逆転はどこですか? 基本的な考え方は、この質問に答えることが不可能なことを理解せずに、 インターフェースは実装ではなく、それらを使用するクライアントに属するということです。 インターフェイス名IBarは誤解を招くものであり、バンドルIBar + Bar全体を考慮するようになります。 同時に、IBarの真の所有者はFooクラスであり、これを考慮すると、FooとBarの間の通信の方向は本当に逆になります。



画像






依存性注入



結果のコードを見ると、注意深い読者は、中間抽象化の導入にもかかわらず、FooクラスがBarクラスのインスタンス化に依然として責任があることに気付くでしょう。 明らかに、これは正確に期待できる区分ではありません。



 public class Foo { private IServer itsServer; public Foo() { itsServer = new Bar(); } }
      
      





Fooクラスをこのような不愉快な義務から救うには、インスタンス化コードを別の場所に持っていき、そこにカプセル化するのがいいでしょう(私たちは皆非常に実用的で、何も二度書くのは好きではないからです)。 これを行うには2つの方法があります-Service LocatorまたはDependency Injectionを使用します。



Service Locatorは、抽象化とその実装の間の対応のようなレジスタです。 興味のあるインターフェイスを彼にフィードし、代わりに特定のクラスの既製のインスタンスを取得します。 次のようになります。



 public class Foo { private IServer itsServer; public Foo() { itsServer = ServiceLocator.Resolve<IServer>(); } }
      
      





ニュアンスは、Fooクラスは現在Barクラスから完全に独立しているが、インスタンス化を制御していることです。 すでに知っているように、これは制御フローを逆にすることで回避できます。 このコントロールを何らかの外部メカニズムの手に渡します。 依存性注入は、IoCコンテナーと呼ばれるフレームワークの形式で実装されるこのようなメカニズムです。



 public class Foo { private IServer itsServer; public Foo(IServer server) { itsServer = server; } }
      
      





おわりに



実際、IoCコンテナーは非常に愚かな名前であるため、さらに悪いことを思い付くのは困難です。 実際に何をするかについては何も言わず、毎日何十人ものプログラマーを誤解させています。 定義上、制御の反転を実装し、一部の汎用コードのラッパーであるため、フレームワークはすべてIoCコンテナーと呼ぶことができます。 この用語は非常にうんざりしていた(そして今もそうである)ために、 Martin Fowlerは別のもの-中毒の導入-を思いつきました。



まとめると。 Dependency Inversionを使用して抽象化でモジュールを分離し、 Dependency Injectionを使用して手動でインスタンス化を取り除き、これをInversion of Controlの原理に基づいて構築されたフレームワークを通じて実装します。 また、これは同義語ではないため、 IoCコンテナは、すべての人を1つの不幸な用語と密接に混同する方法の代表例です。



この小さな作品で、これらのことの違いを伝えることができたので、二度と混同することはないでしょう。 そして、同僚の一人が混同した場合、あなたは彼らに何が悪いのかを簡単かつ明確に説明することができます。



All Articles