如何在JAVA中使用带有重载的Double Dispatch?

FL0*_*0Nn 1 java double design-patterns concept dispatch

我正在尝试在JAVA中创建一个双重调度以使用重载方法。

public abstract class ComposantOrdi {
    protected void equiv(ComposantOrdi c){
        Equivalence.equiv(this, c);
    }
}

public class Montage extends ComposantOrdi{
    protected void equiv(Montage montage){
        Equivalence.equiv(this, montage);
    }
}

public class Equivalence {
    public static void equiv(Montage m, ComposantOrdi c){
        System.out.println("Montage - ComposantOrdi");
    }

    public static void equiv(Montage m, Montage c){
        System.out.println("Montage - Montage");
    }

    public static void equiv(ComposantOrdi m, ComposantOrdi c){
        System.out.println("ComposantOrdi - ComposantOrdi");
    }
}
Run Code Online (Sandbox Code Playgroud)

对于这个例子,我创建两个对象

Montage m2 = new Montage();
ComposantOrdi m3 = new Montage();

m3.equiv(m2);
m3.equiv(m3);
m3.equiv((Montage)m3);
Run Code Online (Sandbox Code Playgroud)

结果是:

ComposantOrdi - ComposantOrdi
ComposantOrdi - ComposantOrdi
ComposantOrdi - ComposantOrdi
Run Code Online (Sandbox Code Playgroud)

但是我想使用Montage类的重载方法,并得到这样的东西:

Montage - Montage
Montage - Montage
Montage - Montage
Run Code Online (Sandbox Code Playgroud)

我可能不理解双重派遣,但是请您告诉我我做错了什么吗?

Jan*_*nis 5

您在代码中执行的操作是单次调度(而不是双重调度-下文解释),因为在运行时仅评估一种具体的子类型会影响结果(对象本身将传递为this)。

另外ComposantOrdiMontage提供不同的方法(检查参数:ComposantOrdigets ComposantOrdiwhile Montagegets Montage)。如果调用超类的equiv方法,则无法获得像Montage-Montage这样的结果,因为每个传递的内容Montage都隐式转换为ComposantOrdi。像这种调用超类的方法一样,结果的第二部分不能是ComposantOrdi

此外,如果你调用父类的方法关键字this

Equivalence.equiv(this,c);

由超类触发,这意味着即使对象是a,Montage它也将自身传递为ComposantOrdi

因此:调用超类的方法只能产生输出ComposantOrdi-ComposantOrdi

对于像Montage-Montage这样的输出,您需要调用子类的方法equiv,这意味着:

  • 您需要将equiv呼叫的接收者引用为Montage(参见m2,而不是m3
  • 你必须传递一个Montage对象

因为这样关键字在输出的第一部分this被触发Montage必须是Montage。第二部分也是Montage,因为Java在不需要时不会隐式转换对象。这就是为什么Montages选择以as作为参数的重载方法的原因。

因此:调用子类的方法只能产生输出Montage-Montage

equiv永远不会调用等价方法的混合版本。


说明双重分配机制:

我认为双重派遣机制存在根本性的误解。因此,让我解释一下。在继续介绍双调度机制之前,我将开始解释单调度。

单一调度:单一调度表示您调用对象的方法,并且已执行的行为(方法调用的结果)取决于对象的具体类型。通常,这称为多态性,是使用抽象方法或方法重写实现的。

假设您根据下图有一个班级系统。将Client持有的名单Shapes。要绘制所有内容,它遍历列表并调用paint每个 列表Shape。当班级Triangle在屏幕上绘制一个三角形时,则Square绘制一个正方形。通过不考虑具体的子类型,Shapes可以在运行时确定执行的行为。

换句话说,paint方法的调用结果取决于Shape接口派生类的具体子类型。由于只有一个具体的子类型可以确定运行时所执行的行为,所以paint方法的调用是单个调度。

在此处输入图片说明

双重调度:使用双重调度机制,执行的行为在运行时受到两种具体子类型的影响。像这样,您将跨越一个行为矩阵,并对其进行动态评估。

如果您根据下面的图片修改类系统,则客户端触发的绘制机制取决于两个对象- Shape和一个Painter。客户端调用该paint方法并注入Painter。然后,Shape传递本身就像this的重载方法之一一样Painter

这样就Client触发了绘制机制,而又不知道以哪种颜色绘制哪种形状。例如,如果其画家为a GreenPainterShape为a,Triangle则屏幕上会出现一个绿色三角形。

在此示例中,双重分配机制是通过调用Shapes' paint方法触发的。

您应该看看使用双重分配机制的访客模式

在此处输入图片说明 在此处输入图片说明