問題は、メソッド シグネチャが Java のコンパイル時にバインドされるため、宣言された型によって呼び出されるメソッドが決定されることです。
ブックJava Puzzlersのパズル作成者「Making a Hash of It」も参照してください。
二重ディスパッチと訪問者パターンを使用できます。次のようになります。
Num_int A = new Num_int( );
Num B = new Num_int( );
Num C = new Num_double( );
Num_printer p = new Num_printer();
A.accept(p);
B.accept(p);
C.accept(p);
Num_int.accept(...)
メソッドとメソッドはどちらも次のNum_double.accept(...)
ようになります。
public class Num_int extends Num {
public void accept(Num_visitor v) {
v.visit(this); // from this scope, `this` has a declared type of `Num_int`
// so at compile time this is binded to signature visit(Num_double)
}
}
public class Num_double extends Num {
public void accept(Num_visitor v) {
v.visit(this); // from this scope, `this` has a declared type of `Num_double`
// so at compile time this is binded to signature visit(Num_double)
}
}
これらのメソッドはほとんど同じですが、メソッドが親クラスに抽出されないことが重要です。親クラスで抽象化するところまで行きます:
public class Num {
public abstract void accept(Num_visitor);
}
class 内からNum
、this
is は宣言された typeNum
です。メソッドがここで定義されている場合accept
、コンパイル時のバインディングは署名になりvisit(Num)
ます。同じ元の問題が再び発生します。
最後に、は次のNum_printer
ようになります。
public class Num_printer implements Num_visitor {
public void visit(Num_int n) {
System.out.println("int");
}
public void visit(Num_double n) {
System.out.println("double");
}
}