ich seit den beiden oben genannten Antworten auf diese hinzuzufügen entschieden etwas unvollständig. Ich war selbst neugierig auf dieses Thema, konnte aber keine Antwort finden und musste meine eigene Analyse machen. Im Allgemeinen gibt es zwei Ansätze, die verwendet werden können, um Multi-Methoden in Sprachen wie C++ oder Java zu implementieren, die sowohl den einzelnen dynamischen Versand als auch eine Art Typ- oder Laufzeittyp-Identifikation unterstützen.
Für den Doppelversandfall ist das Besuchermuster am häufigsten (für Arg1-> foo (Arg2)) und ich nehme in den meisten Fällen vor, RTTI und Schalter oder if-Anweisungen zu verwenden. Man kann den Besucher-Ansatz auch auf den n-Fall verallgemeinern, zB durch Arg1-> foo (Arg2, Arg3..ArgN), indem eine Reihe von einzelnen Nachrichten verkettet wird, die Methoden in einer baumartigen Struktur aufrufen, die sich vom Typ der Argumente bis zu einigen unterscheiden k und spalte die Anzahl der Wege des k + 1 Arguments. Zum Beispiel für einen einfachen Fall von Triple-Versand und nur zwei Instanzen jeden Typs:
interface T1 {
public void f(T2 arg2, T3 arg3);
}
interface T2 {
public void gA(A a, T3 arg3)
public void gB(B b, T3 arg3)
}
interface T3 {
public void hAC(A a,C c);
public void hAD(A a,D d);
public void hBC(B b,C c);
public void hBD(B b,D d);
}
class A implements T1 {
public void f(T2 arg2, T3 arg3) {
arg2->gA(this,arg3);
}
}
class B implements T1 {
public void f(T2 arg2, T3 arg3) {
arg2->gB(this,arg3);
}
}
class C implements T2 {
public void gA(A a,T arg3) {
arg3->hAC(a, this);
}
public void gB(B b,T arg3) {
arg3->hBC(b, this);
}
}
class D implements T2 {
public void gA(A a,T arg3) {
arg3->hAD(a, this);
}
public void gB(B b,T arg3) {
arg3->hBD(b, this);
}
}
class E implements T3 {
public void hAC(A a,C c) {
System.out.println("ACE");
}
public void hAD(A a,D d) {
System.out.println("ADE");
}
public void hBC(B b,C c) {
System.out.println("BCE");
}
public void hBD(B b,D d) {
System.out.println("BDE");
}
}
class F implements T3 {
public void hAC(A a,C c) {
System.out.println("ACF");
}
public void hAD(A a,D d) {
System.out.println("ADF");
}
public void hBC(B b,C c) {
System.out.println("BCF");
}
public void hBD(B b,D d) {
System.out.println("BDF");
}
}
public class Test {
public static void main(String[] args) {
A a = new A();
C c = new C();
E e = new E();
a.f(c,e);
}
}
Obwohl der Ansatz verallgemeinert das Problem liegen auf der Hand. Für jede Endpunktfunktion müssen im schlechtesten Fall n-1 Dispatch-Funktionen geschrieben werden.
Man kann etwas ähnliches mit Laufzeittypidentifikation über den instanceOf Betreiber erreichen:
class Functions
{
static void f(A a,C c,E e) {
System.out.println("ACE");
}
static void f(A a,C c,F f) {
System.out.println("ACF");
}
static void f(A a,D d,E e) {
System.out.println("ADE");
}
static void f(A a,D d,F f) {
System.out.println("ADF");
}
static void f(B b,C c,E e) {
System.out.println("BCE");
}
static void f(B b,C c,F f) {
System.out.println("BCF");
}
static void f(B b,D d,E e) {
System.out.println("BDE");
}
static void F(B b,D d,F f) {
System.out.println("BDF");
}
static void dispatch(T1 t1, T2 t2, T3 t3) {
if(t1 instanceOf A)
{
if(t2 instance of C) {
if(t3 instance of E) {
Function.F((A)t1, (C)t2, (E)t3);
}
else if(t3 instanceOf F) {
Function.F((A)t1, (C)t2, (F)t3);
}
}
else if(t2 instance of D) {
if(t3 instance of E) {
Function.F((A)t1, (D)t2, (E)t3);
}
else if(t3 instanceOf F) {
Function.F((A)t1, (D)t2, (F)t3);
}
}
}
else if(t1 instanceOf B) {
if(t2 instance of C) {
if(t3 instance of E) {
Function.F((B)t1, (C)t2, (E)t3);
}
else if(t3 instanceOf F) {
Function.F((B)t1, (C)t2, (F)t3);
}
}
else if(t2 instance of D) {
if(t3 instance of E) {
Function.F((B)t1, (D)t2, (E)t3);
}
else if(t3 instanceOf F) {
Function.F((B)t1, (D)t2, (F)t3);
}
}
}
}
}
Die zweite Lösung wahrscheinlich weiter vereinfacht Reflexion verwendet werden kann.
Wird Ihr Beispiel even kompilieren? (Anzahl an Operand-Konvertierungen) und könnten Sie ein bisschen mehr klären, was das Problem ist? Es ist eher unklar, was Sie gerade suchen – n247s
Ich habe nicht die Konstruktoren geschrieben, so dass es nicht kompiliert, es ist nur ein Beispiel. Ich möchte Multiplication :: eval (Integer, Matrix) aufrufen, wenn das aufgerufene Objekt den statischen Typ Operator und Laufzeittyp Multiplikation hat und seine Argumente statischen Typ Operand und Laufzeittypen Integer und Matrix haben. Es gibt ein Muster dafür, wenn die eval-Methode nur ein Argument hat, heißt es multiples dispatch. Ich möchte das gleiche für 2 (oder mehr) Argumente. – biowep
Sobald Sie "Operator mul;" definieren, sind Sie auf den durch "Operator" definierten Vertrag beschränkt. Wenn Sie also die Methode 'eval (Integer, Matrix)' in der Klasse 'Operator' (oder einem ihrer Eltern) nicht definieren, können Sie sie nicht aufrufen. Anstatt es vom Typ "Operator" zu deklarieren, können Sie es in "Multiplikation" ändern. – nickb