制御の反転

制御の反転は、フレームワークを使用するときに発生する一般的な現象です。 実際、それはしばしばフレームワークの決定的な特徴とみなされています。



簡単な例を見てみましょう。 コマンドラインを使用してユーザーから情報を受け取るプログラムを書いていると想像してください。 私はこのようなことをすることができます:



#ruby puts 'What is your name?' name = gets process_name(name) puts 'What is your quest?' quest = gets process_quest(quest)
      
      







この状況では、私のコードが実行を制御します。いつ質問するか、いつ答えを読むか、いつ結果を処理するかを決定します。



ただし、同様の目的でウィンドウシステムを使用した場合、ウィンドウで機能するものを記述します。

  require 'tk' root = TkRoot.new() name_label = TkLabel.new() {text "What is Your Name?"} name_label.pack name = TkEntry.new(root).pack name.bind("FocusOut") {process_name(name)} quest_label = TkLabel.new() {text "What is Your Quest?"} quest_label.pack quest = TkEntry.new(root).pack quest.bind("FocusOut") {process_quest(quest)} Tk.mainloop()
      
      





現在、制御フローの2つのプログラムには大きな違いがあります。特に、 process_nameメソッドとprocess_questメソッドが呼び出されるときの時間管理に大きな違いがあります。 コマンドラインの例では、これらのメソッドがいつ呼び出されるかを制御しますが、ウィンドウアプリケーションの例では、いいえ。 代わりに、ウィンドウシステムに制御を渡します( Tk.mainloopコマンド)。 次に、フォームの作成時に構成した関係に基づいて、メソッドを呼び出すタイミングを決定します。 管理は逆になります-フレームワークを制御するのではなく、私を制御します。 この現象は、制御の反転と呼ばれます( ハリウッドプリンシパルとも呼ばれます-「電話しないでください、電話してください 」- ハリウッド原則-「電話しないで、電話します」 )。



フレームワークの重要な特徴の1つは、フレームワークをニーズに適合させるためにユーザーが定義したメソッドは、ほとんどの場合、ユーザーのアプリケーションコードからではなく、フレームワーク自体の内部で呼び出されることです。 フレームワークは、アプリケーションのアクションの調整とシーケンスにおいてメインプログラムの役割を果たすことがよくあります。 この制御の反転により、フレームワークは拡張可能なアプリケーションスケルトンとして機能することができます。 ユーザーが提供するメソッドは、特定のアプリケーション用にフレームワークで定義された一般的なアルゴリズムを適合させます。



ラルフ・ジョンソンとブライアン・フット。




制御の反転は、フレームワークとライブラリを区別する重要な部分です。 ライブラリは、基本的には呼び出すことができる関数のコレクションであり、最近ではクラスに分類されています。 各呼び出しは何らかの作業を行い、ユーザーに制御を返します。



フレームワークは、組み込みの動作を備えた抽象的な設計を具体化します。 それを使用するには、フレームワークのさまざまな場所に、継承を介して、または独自のクラスを接続して、コードを追加する必要があります。 その後、フレームワークコードはコードを呼び出します。



コードを接続して後で呼び出すためのさまざまな方法があります。 前のルビーの例では、テキストフィールドのbindメソッドを呼び出します。このメソッドは、イベント名とクロージャーを引数として取ります。 テキストフィールドがイベントを検出するたびに、クロージャーからコードを呼び出します。 このようなクロージャーの使用は非常に便利ですが、多くの言語ではサポートされていません。



これを行う別の方法は、フレームワークがイベントとこれらのイベントをサブスクライブするユーザーコードを検出するようにすることです。 .NETは、言語を使用してウィジェットでイベントを宣言できるプラットフォームの好例です。 デリゲートを使用して、メソッドをイベントに割り当てることができます。



上記のアプローチ(それらは同じです)は、孤立した場合に適していますが、特定の数の呼び出しを単一の拡張ユニットに結合する必要がある場合があります。 この場合、フレームワークは、対応する呼び出しのためにコードで実装する必要があるインターフェイスを決定できます。



EJBは、このスタイルの制御反転の良い例です。 セッションBeanを開発する場合、ライフサイクルのさまざまなポイント/状態でEJBコンテナによって呼び出されるさまざまなメソッドを実装できます。 たとえば、 SessionBeanインターフェースにはejbRemoveejbPassivate (2次ストレージに保存)、およびejbActivate (受動状態から復元)メソッドがあります。 これらのメソッドの呼び出しを制御することはできません。何をするかだけです。 コンテナは私たちを呼び出しますが、私たちはそれを呼び出しません。



翻訳メモ、例:

 public class EjbExample implements SessionBean { public void ejbActivate() throws EJBException, RemoteException { // do some processing on session object became active } public void ejbPassivate() throws EJBException, RemoteException { // do some processing on session object became passive } public void ejbRemove() throws EJBException, RemoteException { // do some processing before the end of life of session object } public void setSessionContext(SessionContext sessionContext) throws EJBException, RemoteException { // interface dependency injection } }
      
      





これらは制御の反転の複雑なケースですが、より簡単な状況でこれに遭遇します。 テンプレートメソッドは良い例です。スーパークラスは制御フローを定義し、サブクラスはそれを継承してメソッドをオーバーライドするか、抽象メソッドを実装します。 たとえば、JUnitでは、フレームワークコードはテストを作成およびクリアするためにsetUpおよびtearDownメソッドを呼び出します。 呼び出しがあり、コードが反応します-これも制御の反転です。



翻訳メモ、例:

 public class SomeTest extends TestCase { protected void setUp() throws Exception { super.setUp(); // make some preparation for the test, eg setup database connection } public void testSomeLogic() { // test some functionality } protected void tearDown() throws Exception { // cleanup after test has finished super.tearDown(); } }
      
      





現在、IoCコンテナの数が増えているため、制御の反転の意味に混乱が生じています。 一部の人々は、これらのコンテナが使用する特定の制御反転スタイル( 依存性注入など)と一般原則を混同しています。 IoCコンテナは通常EJBと競合するものと見なされますが、EJBは逆制御を使用するため、これは少し混乱します(皮肉なことです)。



語源:私が知る限り、制御の逆転という用語は、1988年に雑誌Object-Oriented Programmingに掲載されたJohnson and Foote Designing Reusable Classesの研究で初めて明らかになりました。 この作品は年齢に長けているものの1つです。15年経っても読むことができます。 彼らはこの言葉を他のどこかから取ったと信じていますが、どこから来たのか覚えていません。 その後、この用語はオブジェクト指向のコミュニティに浸透し、「 ギャングオブフォー 」という本に再登場しました。 より美しい同義語「Hollywood Principle」は、1983年のMesaでのRichard Sweetの作品に由来ているようです。 開発目標のリストに、彼は次のように書いています。電話をかけないで、電話をかけ直します(ハリウッドの法律)。ユーザーがモデルに「コマンドを求めて」実行します。 John VlissidesがC ++のコラムを書いており、The Hollywood Principleと呼ばれるコンセプトの良い説明が掲載されています 。 (語源の助けをしてくれたBrian FooteとRalph Johnsonに感謝します)。



UPD: 例が追加されました。



All Articles