オブジェクト指向プログラミングにおいて、委譲とは、あるオブジェクト(受信側)のメンバー(プロパティまたはメソッド)を、別の元のオブジェクト(送信側)のコンテキストで評価することを指します。委譲は、送信側オブジェクトの責任を受信側オブジェクトに渡すことで明示的に行うこともできます。これは、どのオブジェクト指向言語でも可能です。また、言語のメンバー検索ルールによって暗黙的に行うこともできます。暗黙的な委譲には、言語がこの機能をサポートしている必要があります。暗黙的な委譲は、プロトタイプベースのプログラミングにおける動作再利用の基本的な方法であり、クラスベースのプログラミングにおける継承に相当します。言語レベルで委譲をサポートする最もよく知られた言語は、Selfです。Self は、 self 呼び出し時のメソッド検索で使用される可変の親スロットの概念を通じて委譲の概念を取り入れています。JavaScriptもその一つです。JavaScriptの委譲を参照してください。
委譲という用語は、オブジェクト間のさまざまな関係にも漠然と使用されます。詳しくは委譲 (プログラミング)を参照してください。よく混同される概念は、単に別のオブジェクトを使用することですが、これはより正確にはコンサルテーションまたは集約と呼ばれます。また、あるオブジェクトのメンバーを別のオブジェクトの対応するメンバーを評価することによって評価すること、特に受信オブジェクトのコンテキストで評価することは、より正確には転送と呼ばれます(ラッパー オブジェクトがラップされたオブジェクトに自身を渡さない場合)。[ 1 ] [ 2 ] [ a ]委譲パターンは、委譲を実装するためのソフトウェア設計パターンですが、この用語はコンサルテーションまたは転送にも漠然と使用されます。
プログラミング言語の機能としての委譲という概念は、いわゆる自己呼び出しをディスパッチするためのメソッド検索ルールを利用するものであり、リーバーマンが1986年の論文「オブジェクト指向システムにおける共有動作の実装のためのプロトタイプオブジェクトの使用」で定義した。
委譲は動的バインディングに依存しており、特定のメソッド呼び出しが実行時に異なるコードセグメントを呼び出す必要がある。macOS (およびその前身であるNeXTStep ) 全体で、プログラム コンポーネントの動作をカスタマイズする手段として使用されている。 [ 3 ]このクラスはプログラム固有のデリゲートを受け取り、必要に応じてデフォルトの動作をオーバーライドできるため、単一の OS 提供クラスを使用してウィンドウを管理するなどの実装が可能になる。たとえば、ユーザーが閉じるボックスをクリックすると、ウィンドウマネージャはデリゲートに windowShouldClose: 呼び出しを送信し、ウィンドウの内容によって表される未保存のデータがある場合、デリゲートはウィンドウを閉じるのを遅延させることができる。
委任は、自己の遅延バインディングとして特徴づけられ(転送とは区別される):[ 4 ]
self親の(または) 変数に送信されたメッセージは、this最初にメッセージを受信したオブジェクトに「戻ってきます」。
つまり、self受信オブジェクトのメソッド定義内の は、定義時(コンパイル時や関数がオブジェクトにアタッチされる時など)にはそのオブジェクトに静的にバインドされるのではなく、評価時に元のオブジェクトにバインドされます。
プログラムコードの可読性と理解度を高めるために、場合によっては継承よりも委譲の方が好ましいと主張されてきた。 [ 5 ]明示的な委譲はかなり広く普及しているにもかかわらず、主要なプログラミング言語で委譲を継承の代替モデルとして実装しているものは比較的少ない。委譲と継承の正確な関係は複雑であり、両者を同等と考える著者もいれば、一方を他方の特殊なケースと考える著者もいる。[ 6 ]
メソッド検索ルールによる委譲をサポートする言語では、メソッドのディスパッチは、継承における仮想メソッドの場合と同様に定義されます。つまり、メソッド検索時に常に最も具体的なメソッドが選択されます。したがって、たとえ(オブジェクト参照ではなく委譲リンクを介して)他のオブジェクトに制御を移したとしても、メソッド検索の開始点は元のレシーバーエンティティになります。
委譲の利点は、実行時に実行でき、特定の型のエンティティのサブセットのみに影響を与え、実行時に削除することもできる点です。一方、継承は通常、インスタンスではなく型を対象とし、コンパイル時のみに制限されます。また、継承は静的に型チェックが可能ですが、委譲はジェネリクスを使用しない限り、一般的には静的型チェックができません(ただし、委譲の制限付きバージョンは静的に型安全になる可能性があります[ 7 ])。委譲は「特定のオブジェクトに対する実行時継承」と表現できます。
以下は、C#やJavaのような言語で記述された擬似コードの例です。
class A { void foo () { // "this"は他の言語では "current"、"me" 、"self" とも呼ばれますthis.bar (); }void bar () { print ( "a.bar" ); } }class B { private delegate A a ; // 委譲リンクpublic B ( A a ) { this . a = a ; }void foo () { a.foo (); // aインスタンスに対してfoo()を呼び出す}void bar () { print ( "b.bar" ); } }a = new A (); b = new B ( a ); // 2つのオブジェクト間の委譲を確立するを呼び出すと、 のコンテキスト内でが元の送信オブジェクトを参照するため、 b.barb.foo()が出力されます。 の結果生じる の曖昧さは、オブジェクト schizophreniaと呼ばれます。thisbathis
暗黙のthisパラメータを明示的なパラメータに変換すると、呼び出し (デリゲートB付き) は、メソッド解決には の型を使用し、引数にはデリゲートオブジェクトを使用してに変換されます。aa.foo()A.foo(b)abthis
継承を用いた場合、同様のコード(解決がオブジェクトではなくクラスに基づいていることを強調するために大文字を使用)は次のようになります。
class A { void foo () { this . bar (); }void bar () { print ( "A.bar" ); } }class B extends A { public B () {}void foo () { super.foo (); // スーパークラス(A)のfoo()を呼び出す}void bar () { print ( "B.bar" ); } }b = new B ();呼び出しの結果はB.barb.foo()になります。この場合、は明確です。単一のオブジェクト があり、サブクラスのメソッドに解決されます。thisbthis.bar()
一般的にプログラミング言語は、言語概念としてこの珍しい形式の委譲をサポートしていませんが、いくつかの例外があります。
言語が委譲と継承の両方をサポートしている場合、両方のメカニズムを同時に利用して二重継承を行うことができます。
class C extends A { delegationlink D d ; }これはメソッド検索に関する追加のルールを必要とします。なぜなら、検索パスが2つ存在するため、最も具体的なメソッドとして指定できるメソッドが2つ存在する可能性があるからです。
委譲は、エンティティ間でコードやデータを共有するための低レベルのメカニズムと説明できます。したがって、委譲は他の言語構造の基盤となります。特に役割指向プログラミング言語は委譲を利用してきましたが、古い言語は委譲を使用していると主張しながら実際には集約を使用していました。これは不正行為と考えるべきではなく、単に委譲の意味が複数あることを示しているだけです(上記参照)。
最近では、分散型委任に関する研究も行われており、例えば検索エンジンのクライアント(格安ホテルを探す場合)は、委任を利用した共有エンティティを使用して、最適な検索結果や一般的な再利用可能な機能を共有できるようになっています。
アスペクト指向プログラミングにおけるアドバイス解決のための委任も、2003年にエルンストとローレンツによって提案されている。
区別する:
この論文では、純粋な転送ベースのオブジェクト構成を補完するものとして、オブジェクトベースの継承(委譲とも呼ばれる)を提案します。クラスベースのオブジェクトモデルへの委譲の型安全な統合を示し、転送ベースのコンポーネント相互作用が直面する問題をどのように克服するか、コンポーネントの独立した拡張性や予期しない動的なコンポーネント適応をどのようにサポートするかを示します。
{{cite book}}: CS1 maint: bot: 元の URL の状態が不明です (リンク){{cite book}}:|journal=無視されました (ヘルプ) CS1 メンテナンス: 場所が見つかりません パブリッシャー (リンク)