ビジターパターンについて読んでいますが、ダブルディスパッチと同じように見えます。 2つの間に違いはありますか。 2つの用語は同じことを意味します。
それらは、ダブルディスパッチがネイティブでサポートされていない一部の言語では、マルチディスパッチサロゲートを持つために2つ(またはそれ以上)のシングルディスパッチを連結する方法としてビジターパターンにつながるという異なる概念に由来しています。
複数のディスパッチのアイデアは-基本的に-次のような呼び出しを許可します
void fn(virtual base_a*, virtual base_b*);
(注:クラスメンバーとしてではなく、これはC++ではありません!)
次のようにオーバーライドできます
_void fn(virtual derived_a1*, virtual derived_b1*);
void fn(virtual derived_a2*, virtual derived_b1*);
void fn(virtual derived_a1*, virtual derived_b2*);
void fn(virtual derived_a2*, virtual derived_b2*);
_
それで、呼び出すとき
_fn(pa, pb)
_
呼び出しは、pa
とpb
の両方の実際のランタイムタイプに一致するオーバーライドにリダイレクトされます。 (これを任意の数のパラメーターに一般化できます)
C++、C#、Javaなどの言語では、このメカニズムは存在せず、ランタイム型のディスパッチは基本的に1つのパラメーターでのみ機能します(つまり、1つだけなので、関数自体をクラスのメンバーにすることで、関数内で暗黙的に行われます:
つまり、疑似コード
_void fn(virtual base_a*, base_b*)
_
(本当のC++)になる
_class base_a
{
public:
virtual void fn(base_b*);
}
_
ここでは、_base_b
_の前にvirtual
がなくなっていることに注意してください。のような呼び出し
pa->fn(pb)
paがderived_a2を指し、pbがderived_b1を指す場合は、drived_a2 :: fn(base_b *)にディスパッチされます。そこにderived_a2 :: fn(derived_b1 *)があるかどうかは関係ありません。実行pbが指すオブジェクトの-timeタイプは考慮されません。
訪問者パターンのアイデアは、別の仮想ディスパッチを呼び出す(最終的には戻る)オブジェクトの仮想ディスパッチを呼び出すことです。
_class base_a
{
public:
virtual void fn(base_b*)=0;
virtual void on_visit(derived_b1*)=0;
virtual void on_visit(derived_b2*)=0;
};
class base_b
{
public:
virtual void on_call(derived_a1*)=0;
virtual void on_call(derived_a2*)=0;
};
//forward declarations, to allow pointers free use in other decls.
class derived_a1;
class derived_b1;
class derived_a1: public base_a
{
public:
virtual void fn(base_b* pb) { pb->on_call(this); }
virtual void on_visit(derived_b1* p1) { /* useful stuff */ }
...
};
class derived_b1: public base_b
{
public:
virtual void on_call(derived_a1* pa1) { pa1->on_visit(this); }
...
};
_
今回、pa->fn(pb)
のような呼び出しは、paがderived_a1を指し、pbがderived_b1を指している場合、最終的にderived_a1::on_visit(derived_b1*)
に行きます。
訪問者パターンは、二重ディスパッチの動作を実装するoneソリューションです。他にもいくつかの解決策があります。用語double dispatch自体は、ソリューションについての考えを与えません。実際、それは訪問者パターン。
C#(4.0)では、dynamic
キーワードを使用して二重ディスパッチを実装できます。この場合、ビジターパターンは必要ありません。 dynamic
キーワードを使用したdouble-dispatch問題の解決策は次のとおりです。
Dynamic Dispatchは、一般に、ランタイム情報に基づいてメソッドにディスパッチするconceptを指します。ほとんどのOOシステム(Java/C#/ C++など))は通常、virtual
メソッドを介して動的ディスパッチを実装します(すべてのメソッドが仮想であるかどうかは言語によって異なります)。単一のメソッド引数(暗黙のオブジェクト参照)に従ってディスパッチします。
一般に、任意の数の要素に従ってディスパッチしたい場合があります。たとえば、ダブルディスパッチは、メソッドの2つの引数に従ってディスパッチするための要件/機能です。
一方、Visitor Patternは、一般的にマルチディスパッチのimplementationであり、特にこのような場合のダブルディスパッチ= OOシステム。
二重ディスパッチは技術的な問題であり、言語によってはさまざまな方法で解決できます。一部の言語は二重ディスパッチを直接サポートしています。ビジターパターンは、さまざまな問題を解決するために使用できるパターンです。 C++の場合、これはダブルディスパッチに使用される最も頻繁な(唯一ではない)ソリューションですが、それだけに使用されるわけではなく、ダブルディスパッチをサポートする言語でも役立つ場合があります。