い結果を得ることになる.例えば,Rectangle@5クラスのオブジェクトがまず 生成され,setX()とsetY()メソッドによって,座標(-1,-1)から座標(2,2)に移
動した(つまり,インスタンス変数xとyにそれぞれ2が代入される)とする.そ
の時,なんらかの理由で,そのオブジェクトをRectangle@4クラスのオブジェ クトへ縮退する必要が生じた時,クラス継承を用いた実行では,オブジェクトの 変換をすることなく,Rectangle@4クラスのオブジェクトとして扱うことがで きる.しかし ,現在の座標が変更したことを(Rectangle@4で宣言されている) インスタンス変数xとyを反映させなければ(つまり,xとyにそれぞれ正の整数 を抽象化した値posを代入する),たとえRectangle@4クラスのオブジェクトと して扱ったとしても正しい結果を得ることはできない.この整合性を保つための コード はプロトタイプ毎に異なるため,三つ目の問題点は解決されない.
仲介オブジェクトに全ての発展したオブジェクトのインターフェースを持たせ,
calleeオブジェクトを直接参照しないことによって,一つ目の問題点を解決してい
る.callerオブジェクトが参照しているオブジェクトは仲介オブジェクトなので,
たとえcalleeオブジェクトが縮退によって異なる(発展前の)オブジェクトに変換
されたとしても,それに合わせてcallerオブジェクトを変化させる必要はない.し たがって,どんな発展度を持つcalleeオブジェクトであっても,間接的に参照で きるので,異なる発展度を持つ全てのオブジェクトを同一的に扱うことができる.
さらに,callerオブジェクトの持つcalleeオブジェクトへの参照を再構成する必要 がなくなるため,二つ目の問題点も解決する.
仲介オブジェクトがメソッド 呼び出しの仲介を行なうことがcallerオブジェクト
やcalleeオブジェクトから抽象実行に必要なコード の分離を可能にする.これが仲
介オブジェクトの機械的な生成を可能とし,三つ目の問題点を解決する.この機 械的な生成の詳細は次の節で詳しく述べる.本技法において,縮退はメソッド 呼 び出し時に発生する.仲介オブジェクトは,発展した全てのオブジェクトへのメ ソッド 呼び出しを全て仲介するので,仲介オブジェクトが縮退を管理することが 可能となる.これによって,callerオブジェクトに縮退に関するコード を記述する 必要がなくなる.さらに,仲介オブジェクトがcalleeオブジェクトの縮退を管理す ることで,calleeオブジェクトは自分自身の縮退の管理から解放される.したがっ て,仲介オブジェクトの構造が本質的なコード と抽象実行に必要なコード との分 離を可能とする.
より具体的に,以下のdispatch()アルゴ リズムは,仲介オブジェクトの機能であ る縮退をともなうメソッド 呼び出しの仲介を表している.
Object dispatch (Method m, Object[] args) int n = canInvoke (callee, m, args);
switch (n) case POSSIBLE:
return m.invoke (callee, args);
case CALLER DEGEN:
throw new NeedDegeneracyException ();
case CALLEE OBJ DEGEN:
degeneracy (callee);
return this.dispatch (m, args);
case CALLEE METH DEGEN:
Method m’ = degeneracyMethod (m);
Object[] args’ = degeneracyData (args);
return m’.invoke (callee, args’);
このアルゴ リズムは,引数としてメソッド とその引数を取り,それぞれ
callerオブジェクトが呼び出したメソッド とその引数を表している.このアルゴ リ
ズムでは,まず,が呼び出し可能かど うかを調べる.ここで,その 検査を#と表している.また,は,仲介オブジェクトが現在参照
しているcalleeオブジェクトを表している.#関数は,(1)縮退を必要
としないことを表す値POSSIBLE,(2)callerオブジェクトの縮退が必要であること
を表す値CALLER DEGEN,(3)calleeオブジェクトにおけるオブジェクトの縮退
が必要であることを表す値CALLEE OBJ DEGEN,(4)calleeオブジェクトにおけ るメソッド の縮退が必要であることを表す値CALLEE METH DEGENのいずれか を返す.
そして,#関数の返す値によって次のように振舞いが変化する.
POS-SIBLEの場合,縮退する必要がないので,そのままメソッド 呼び 出しを行なう.
CALLER DEGENの場合,calleeオブジェクトが抽象的すぎてメソッド 呼び出し
を行ないことを表しているので,callerオブジェクトを管理する仲介オブジェク トに縮退が必要であることを知らせる例外NeedDegeneracyExceptionを発生させ る1.CALLEE OBJ DEGENの場合,まず,calleeオブジェクトの縮退を行なう.そ の縮退をとして表している.そして,再帰的にこのアルゴ リズムを 実行する.この再帰的な呼び出しは,callerオブジェクトとcalleeオブジェクトの 発展度が同じになった時,つまりPOSSIBLEの場合,のメソッド 呼び出しに対す
1dispatch() ア ル ゴ リ ズ ム で は ,こ の 例 外 に 対 す る 例 外 処 理 を 省 略 し て い る が , CALLEE OBJ DEGENの場合と同様の処理を行なうだけである.
る返り値を最終的な値としてcallerオブジェクトに返すことを実現する.最後に,
CALLEE METH DEGENの場合,メソッド の縮退を行ない,再び メソッド 呼び出
しを行なう.ここで,メソッド はに変換され,その実引数はに 変換される.これらの変換を行なうのが,それぞれdegeneracyMethod()と degen-eracyData()である.