ソフトウェア設計において、制御の反転(IoC )とは、コンピュータプログラムの独自に記述された部分が外部ソース(フレームワークなど)から制御の流れを受け取る設計原則です。「反転」という用語は歴史的なもので、この設計を採用したソフトウェアアーキテクチャは、手続き型プログラミングと比較して制御を「反転」させます。手続き型プログラミングでは、プログラムの独自コードが再利用可能なライブラリを呼び出して汎用的なタスクを処理しますが、制御の反転では、外部コードまたはフレームワークが制御権を持ち、独自コードを呼び出します。
制御の反転は、GUI環境の台頭以来、アプリケーション開発フレームワークで広く使用されており[ 1 ] [ 2 ] 、GUI環境とWebサーバーアプリケーションフレームワークの両方で引き続き使用されています。制御の反転により、アプリケーションプログラマによって定義されたメソッドによってフレームワークを拡張できます。 [ 3 ]
イベント駆動型プログラミングは、多くの場合、IoC(制御の相互運用性)を用いて実装されます。これにより、カスタムコードはイベントの処理のみに専念でき、イベントループやイベント/メッセージのディスパッチはフレームワークまたはランタイム環境によって処理されます。Webサーバーアプリケーションフレームワークでは、ディスパッチは通常ルーティングと呼ばれ、ハンドラはエンドポイントと呼ばれることがあります。
「制御の反転」というフレーズは、Java プログラマーのコミュニティでは、Spring Framework などの Java フレームワークの「IoC コンテナ」で発生する依存性注入(サービスを必要とするオブジェクトにサービスを渡す) のパターンを具体的に指すためにも別々に使用されるようになりました。[ 4 ]この異なる意味での「制御の反転」は、フレームワークに制御フロー(アプリケーション コードの実行時間、例えばコールバックの制御)を付与するという本来の意味ではなく、アプリケーション オブジェクトが使用する依存関係の実装に対するフレームワークの制御を付与することを指します。[ 5 ]
例えば、従来のプログラミングでは、アプリケーションのメイン関数がメニューライブラリに関数呼び出しを行い、利用可能なコマンドのリストを表示して、ユーザーに1つを選択するように促すことがあります。[ 6 ]ライブラリは選択されたオプションを関数呼び出しの値として返し、メイン関数はこの値を使用して関連付けられたコマンドを実行します。このスタイルはテキストベースのインターフェースで一般的でした。たとえば、電子メールクライアントは、新しいメールを読み込む、現在のメールに返信する、新しいメールを作成するなどのコマンドを含む画面を表示し、ユーザーがキーを押してコマンドを選択するまでプログラムの実行はブロックされます。
一方、制御の反転では、ウィンドウシステム、メニュー、マウス操作、ツールバーなど、共通の動作要素やグラフィック要素を認識するソフトウェアフレームワークを使用してプログラムを作成します。カスタムコードは、メニュー項目のテーブルを提供したり、各項目にコードサブルーチンを登録したりするなど、フレームワークの「不足部分を補う」役割を果たしますが、ユーザーの操作を監視し、メニュー項目が選択されたときにサブルーチンを呼び出すのはフレームワークです。メールクライアントの例では、フレームワークはキーボードとマウスの両方の入力を追跡し、ユーザーがどちらの方法で呼び出したコマンドも実行できます。同時に、ネットワークインターフェースを監視して新しいメッセージが届いたかどうかを確認し、ネットワークアクティビティが検出されたときに画面を更新することもできます。同じフレームワークをスプレッドシートプログラムやテキストエディタの骨組みとして使用することもできます。逆に、フレームワークはWebブラウザ、スプレッドシート、テキストエディタについては何も知りません。これらの機能を実装するには、カスタムコードが必要です。
制御の反転は、アプリケーション内で連携して動作するものの、再利用可能なコードと問題固有のコードが独立して開発されるという強い意味合いを持つ。コールバック、スケジューラ、イベントループ、テンプレートメソッドは、制御の反転の原則に従う設計パターンの例であるが、この用語はオブジェクト指向プログラミングの文脈で最も一般的に使用される。(依存性注入は、Javaフレームワークによって普及した「依存関係の実装に対する制御の反転」という別の具体的なアイデアの例である。)[ 4 ]
制御の反転は、フレームワークが実行の流れをどのように規定するかを反映して、「ハリウッド原則:こちらから連絡しますので、こちらから連絡します」と呼ばれることがあります。[ 1 ]
このフレーズの語源は1988年に遡るとされていますが[ 7 ] 、 1970年代にマイケル・ジャクソンがジャクソン構造化プログラミング手法で説明したプログラム反転の概念と密接に関連しています[ 8 ] 。ボトムアップパーサーはトップダウンパーサーの反転と見なすことができます。前者の場合、制御はパーサーにありますが、後者の場合、制御は受信側のアプリケーションにあります。
この用語は、マイケル・マットソンが論文で使用し(本来の意味はフレームワークがアプリケーションコードを呼び出すことであり、その逆ではない)[ 9 ]、その後ステファノ・マッツォッキがそこから[ 10 ]、1999年に廃止されたApacheソフトウェア財団のプロジェクトAvalonで普及させ、実行フローの制御に加えて子オブジェクトの依存関係を渡す親オブジェクトを指すようになった。[ 11 ]このフレーズは2004年にロバート・C・マーティンとマーティン・ファウラーによってさらに普及し、後者は用語の起源を1980年代に遡る。[ 7 ]
従来のプログラミングでは、ビジネスロジックの流れは、静的に相互に結び付けられたオブジェクトによって決定されます。制御の反転(IoC)では、流れはプログラム実行中に構築されるオブジェクトグラフに依存します。このような動的な流れは、抽象化によって定義されたオブジェクト間の相互作用によって可能になります。この実行時バインディングは、依存性注入やサービスロケータなどのメカニズムによって実現されます。IoCでは、コンパイル時にコードを静的にリンクすることもできますが、コード自体に直接参照するのではなく、外部構成から記述を読み取って実行するコードを見つけます。
依存性注入では、依存オブジェクトまたはモジュールは、実行時に必要とするオブジェクトに結合されます。プログラム実行中にどのオブジェクトが依存関係を満たすかは、通常、コンパイル時の静的解析ではわかりません。ここではオブジェクト間の相互作用という観点から説明していますが、この原理はオブジェクト指向プログラミング以外のプログラミング手法にも適用できます。
実行中のプログラムがオブジェクト同士をバインドするには、オブジェクトが互換性のあるインターフェースを持っている必要があります。たとえば、クラスは、クラスによって実装されるAインターフェースに動作を委譲することができます。プログラムはとをインスタンス化し、にを注入します。IBABBA
ウェブブラウザは、HTML の DOM イベントに対して制御の反転を実装しています。アプリケーション開発者は、これを使用してdocument.addEventListener()コールバックを登録します。
< ! doctype html > < html lang = "en" > <head> < meta charset = " utf - 8 " > <title> DOMレベル2 </title> </head> <body> <h1> DOMレベル2イベントハンドラ</h1> < div id = " output " > </div><script> var listener = function ( ) { document.getElementById ( " output" ). innerHTML = " <p>登録されたリスナーが呼び出されました。</p>" ; } document.addEventListener ( " click " , listener , true ) ;document.getElementById ( " output" ) . innerHTML = " <p>イベントハンドラが登録されました。ページをクリックすると、Webブラウザがイベントハンドラを呼び出します。</p> " </script> </body> </html>この ASP.NET Core Web アプリケーションのサンプル コードは、Web アプリケーション ホストを作成し、エンドポイントを登録し、フレームワークに制御を渡します。[ 12 ]
var builder = WebApplication.CreateBuilder ( args ); var app = builder.Build ( ); app.MapGet ( " /" , () = > " Hello World!" ) ; app.Run ( ) ;ルーティングは、受信した HTTP リクエストを照合し、それらのリクエストをアプリの実行可能なエンドポイントにディスパッチする役割を担います。エンドポイントは、アプリの実行可能なリクエスト処理コードの単位です。エンドポイントはアプリ内で定義され、アプリの起動時に構成されます。
{{cite web}}: CS1 maint: 複数の名前: 著者リスト (リンク)