委譲
委譲 (delegation) とはオブジェクト指向プログラミングにおいて、あるオブジェクトの操作を一部他のオブジェクトに代替させる手法のこと。
委譲を行うオブジェクトは委譲先オブジェクトへの参照を持ち、必要に応じてその参照を切り替える事で動作にバリエーションを持たせる事ができる。一種の実装遅延、プラグイン機構である。一例としては、オブジェクトの編集を行う時、編集の前処理、後処理を本処理と独立させ委譲先に任せる事で、オブジェクト本体の変更を最小限にとどめ局所性を向上させる、などがある。
操作の代替という観点では他に代理 (Proxy) と呼ばれる手法があるが、この場合は代理側のオブジェクトが実体への参照を保持する事で操作のフィルタを行う概念であり、実装の分離を目的とする委譲とは異なる。
委譲を引き受けるオブジェクトはどのような操作を実装しなければならないか知っている必要があるため、インタフェースと併用される場合が多い。
いくつかの言語ではデザインパターンにおける手法であり、いくつかの言語ではコードで実装されライブラリとして提供されている。struct ExampleInterface
class Something
};
class SomethingDelegator:public ExampleInterface
int main()
class A {
class B {
SelfやJavaScriptといったプロトタイプベースの言語では言語機能として委譲と継承の中間とも言えるプロトタイプ機能を備えており委譲先のオブジェクトを書き換えることはできないものの手軽に委譲ができるようになっている。
プロトタイプを使った委譲の例：
共通の反復処理を提供するオブジェクトとしてIterableを定義。
// Iterableはprototype(委譲先)の要件としてdoEachを要求する。
this.doEach = function( aBlock )
Iterable = function()
BaseCollection = [ 0, 1, 2, 3, 4 ];
BaseCollection.doEach = function( aBlock )
// 配列にselect( aBlock )を追加する。
Iterable.prototype = BaseCollection;
Collection = new Iterable().select( function( aEach ){ return 3 < aEach } );
BaseCollection = { 0: 4, 1: 3, 2: 2, 3: 1, 4: 0 };
BaseCollection.doEach = function( aBlock )
// 連想配列にselect( aBlock )を追加する。
Iterable.prototype = BaseCollection;
Collection = new Iterable().select( function( aEach ){ return 3 < aEach } );
なお、Selfの様に純粋なプロトタイプベースの言語ではprototype変数やnewに相当するものは無い。単純にプロトタイプとなるオブジェクトを委譲先としてオブジェクトを生成する機能のみ備わっているためJavaScriptの様に委譲元を再利用するにはメソッド等サブルーチンの追加が必要となる。
Objective-Cの例を説明する。Objective-Cではデリゲート先のオブジェクトはどんなオブジェクトでも構わない。デリゲートしないときはcodice_1を指定してもよい。Objective-CはC++とは異なり実行時解決を採用しているので、デリゲート先に指定したオブジェクトが必要なメソッドを持っていなくてもコンパイルエラーにはならず、単に何も実行されないだけである。文法上で特殊な扱いはされておらず、平時の記述の枠内で処理される典型的な実装パターンとして用いられる。
あるオブジェクトAがメインウィンドウを持っていて、そのAにメインウィンドウの処理を委譲する場合
[mainWindow setDelegate: self];
codice_2は自分自身を指すポインタである。codice_3内はC言語に対してObjective-Cで拡張された文法で、インスタンス変数codice_4に対してcodice_5メッセージを送っている。
このdelegateを設定することで、Aがメインウィンドウの処理、たとえばウィンドウを閉じる前に何かしたい場合に用いるメソッドcodice_6をかわりに実行するようになる。Aに
-(void)windowWillClose:(NSNotification*)notification
のようなメソッドを用意しておけば、ウィンドウのクラス(codice_7)に修正を加えたり、codice_7を継承したクラスを作らなくても振る舞いをカスタマイズすることができる。
Smalltalkにおける委譲も基本的には他の言語と同じである。
ただし、メッセージ機構を利用することでSmalltalk独特の委譲を行うことが出来る。
Smalltalkは、オブジェクトに対しメッセージが送られた際、メッセージ内のセレクターに該当するメソッドがオブジェクト内に無ければ、そのメッセージはdoesNotUnderstand:メソッドに送られる。この時doesNotUnderstand:メソッドで受け取ったメッセージは自由に他のオブジェクトに送りつけることが出来る。
なお、Objective-CにもdoesNotUnderstand:と同等の仕組みが存在し、同様の処理を記述できる。上記のObjective-Cの委譲もこのメッセージ処理の仕組みを利用している。
委譲用クラスの定義例：
委譲用クラスの使用例:Go言語においては、他の言語と異なり始めから委譲を想定した委譲専用構文を備えている。
Go言語では、表向き継承機能を持っていないが、この委譲構文によって継承に必要とされる殆どの機能を実現できる。例えば多重継承も可能であるが、基底型から派生型のメンバーを呼び出すようなことは出来ない。
下記にGoの委譲機能を使って線分の頂点座標しか表示できない型に対して、Bezier曲線の頂点座標表示能力を付与する例を示す。：
crubyでは標準添付のdelegateライブラリを利用して委譲が使える。