java - 多个参数的多重分派(dispatch)

标签 java oop dynamic parameter-passing dispatch

有没有一种优雅的方法可以在 OO 语言中使用(单个)动态分派(dispatch)为具有 2 个(或更多)参数的方法获得多个分派(dispatch)?

可能的问题示例:

这是一个受 Java 启发的示例。(问题与语言无关!)

// Visitable elements
abstract class Operand {
}
class Integer extends Operand {
    int value;
    public int getValue() {
        return value;
    }
}
class Matrix extends Operand {
    int[][] value;
    public int[][] getValue() {
        return value;
    }
}

// Visitors
abstract class Operator {
    // Binary operator
    public Operand eval(Operand a, Operand b) {
        return null; // unknown operation
    }
}
class Addition extends Operator {
    public Operand eval(Integer a, Integer b) {
        return new Integer(a.getValue() + b.getValue());
    }
}
class Multiplication extends Operator {
    public Operand eval(Integer a, Integer b) {
        return new Integer(a.getValue() * b.getValue());
    }
    // you can multiply an integer with a matrix
    public Operand eval(Integer a, Matrix b) {
        return new Matrix();
    }
}

我有很多运算符和操作数具体类型,但只通过它们的抽象类型引用它们:

Operand a = new Integer()
Operand b = new Matrix();
Operand result;
Operator mul = new Multiplication();
result = mul.eval(a, b); // Here I want Multiplication::eval(Integer, Matrix) to be called

最佳答案

我决定对此进行补充,因为以上两个答案有些不完整。我自己对这个问题很好奇,但找不到答案,所以不得不自己分析。一般而言,有两种方法可用于在 C++ 或 Java 等语言中实现多方法,这些方法同时支持单个动态调度和类似 typeof 或运行时类型识别的东西。

对于双分派(dispatch)情况,访问者模式是最常见的(对于 Arg1->foo(Arg2) ),我认为在大多数情况下比使用 RTTI 和开关或 if 语句更受欢迎。还可以将访问者方法推广到 n 情况,即 Arg1->foo(Arg2,Arg3..ArgN),通过链接一系列调用树状结构中的方法的单个分派(dispatch),这些分派(dispatch)在参数类型上区分到一些k 并拆分 k+1 个参数的方式数。例如,对于三重分派(dispatch)的简单情况,每种类型只有两个实例:

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);
    }
}

尽管该方法概括了问题,但问题非常明显。在最坏的情况下,对于每个端点函数,必须编写 n-1 个调度函数。

可以通过 instanceOf 运算符实现与运行时类型识别类似的功能:

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 );
                }
            }
        }
    }
}

第二种解决方案可能可以使用反射进一步简化。

关于java - 多个参数的多重分派(dispatch),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40386379/

相关文章:

java - 包名应该是ProjectName还是CodeName?

django:为模板提供动态(reportlab)png

python - 谁能解释一下 "out = self(images)"在下面的代码中做了什么

c# - 在c#中将对象转换为子类

c - 如何在 C 中正确设置、访问和释放多维数组?

android - 如何在动态创建的一组 editText 上设置 onFocusChangeListener()?

java - 通过 Push、vaadin 切换附加组件

java - 从另一个 java 类重写该类中的方法(附加到其他方法)

java - Mockito:如何模拟 JodaTime 的界面

java - 从外部包实例化 protected 类