如何在 JAVA 中使用带过载的双分派?
How to use a Double Dispatch with overload in JAVA?
我正在尝试在 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");
}
}
例如我创建了两个对象
Montage m2 = new Montage();
ComposantOrdi m3 = new Montage();
m3.equiv(m2);
m3.equiv(m3);
m3.equiv((Montage)m3);
结果是:
ComposantOrdi - ComposantOrdi
ComposantOrdi - ComposantOrdi
ComposantOrdi - ComposantOrdi
但我想使用 Montage 的重载方法 class
得到这样的东西:
Montage - Montage
Montage - Montage
Montage - Montage
我可能不明白双重派遣,但你能告诉我我做错了什么吗?
一般的JVMs只使用single dispatch:运行时类型只考虑receiver对象;对于方法的参数,考虑静态类型。
如果你想为你的参数进行多次分派,并且你想坚持使用 Java,请查看 MultiJava
如果您的目标是坚持使用普通的香草 java,请阅读其他设计模式,例如 Strategy、Visitor、Observer。这些通常可以解决与 multiple dispatch
相同的问题
你在你的代码中做的是一个单分派(不是双分派——下面的解释)因为只有一个具体的子在运行时评估的类型会影响结果(对象将自身传递为 this
)。
此外ComposantOrdi
和Montage
提供了不同的方法(查看参数:ComposantOrdi
获取ComposantOrdi
而Montage
获取Montage
) .如果调用 superclass' equiv
方法,则无法获得像 Montage - Montage 这样的结果,因为每个传递的 Montage
都被隐式转换到 ComposantOrdi
。就像调用 superclass' 方法一样,结果的第二部分不能是 ComposantOrdi.
此外,如果您调用 superclass' 方法,
中的关键字 this
Equivalence.equiv(this, c);
由 superclass 触发,这意味着即使对象是 Montage
它也会将自身传递为 ComposantOrdi
.
所以:调用superclass'方法只能产生输出ComposantOrdi - ComposantOrdi.
对于 Montage - Montage 这样的输出,您需要调用子 class' 方法 equiv
,这意味着:
- 您需要将
equiv
调用的接收者引用为 Montage
(请参阅主体中的 m2
,而不是 m3
)
- 你必须传入一个
Montage
对象
因为关键字 this
在 Montage
中触发,输出的第一部分必须是 Montage。第二部分也是 Montage 因为 Java 不会在不需要时隐式转换对象。这就是为什么选择以 Montages
作为参数的重载方法。
所以:调用sub class'方法只能产生输出Montage - Montage.
永远不会调用 Equivalence 的 equiv
方法的混合版本。
解释双重调度机制:
我认为双重派遣机制存在根本性的误解。所以让我解释一下。在介绍双分派机制之前,我将开始解释单分派。
单次发送:
单次分派意味着您调用对象的方法,执行的行为(方法调用的结果)取决于对象的具体类型。通常这称为多态性,使用抽象方法或方法覆盖来实现。
假设您有一个 class 系统,如下图所示。 Client
包含 Shapes
的列表。为了绘制所有这些,它循环遍历列表并在每个 Shape
上调用 paint
。当 class Triangle
在屏幕上绘制三角形时,Square
绘制正方形。通过不考虑 Shapes
是哪个具体子类型,执行的行为是在运行时确定的。
换句话说,调用 paint 方法的结果取决于 Shape
接口派生的具体子类型。 paint 方法的调用是 single 分派,因为只有 one 具体子类型决定运行时执行的行为。
DOUBLE DISPATCH:使用 double 调度机制,执行的行为在运行时受到 two 具体子类型的影响。像这样,您跨越了一个动态评估的行为矩阵。
如果根据下图修改class系统,客户端触发的绘制机制依赖于两个对象——Shape
和一个Painter
。客户端调用 paint
方法并注入它的 Painter
。然后 Shape
在 Painter
.
的重载方法之一中将自身作为 this
传递
像这样,Client
在不知道绘制什么颜色什么形状的情况下触发绘制机制。例如,如果它的画家是 GreenPainter
而 Shape
是 Triangle
,那么屏幕上会出现一个绿色三角形。
在此示例中,双重调度机制由 Shapes
' paint
方法的调用触发。
您应该看一下使用双重调度机制的访问者模式。
我正在尝试在 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");
}
}
例如我创建了两个对象
Montage m2 = new Montage();
ComposantOrdi m3 = new Montage();
m3.equiv(m2);
m3.equiv(m3);
m3.equiv((Montage)m3);
结果是:
ComposantOrdi - ComposantOrdi
ComposantOrdi - ComposantOrdi
ComposantOrdi - ComposantOrdi
但我想使用 Montage 的重载方法 class 得到这样的东西:
Montage - Montage
Montage - Montage
Montage - Montage
我可能不明白双重派遣,但你能告诉我我做错了什么吗?
一般的JVMs只使用single dispatch:运行时类型只考虑receiver对象;对于方法的参数,考虑静态类型。
如果你想为你的参数进行多次分派,并且你想坚持使用 Java,请查看 MultiJava
如果您的目标是坚持使用普通的香草 java,请阅读其他设计模式,例如 Strategy、Visitor、Observer。这些通常可以解决与 multiple dispatch
相同的问题你在你的代码中做的是一个单分派(不是双分派——下面的解释)因为只有一个具体的子在运行时评估的类型会影响结果(对象将自身传递为 this
)。
此外ComposantOrdi
和Montage
提供了不同的方法(查看参数:ComposantOrdi
获取ComposantOrdi
而Montage
获取Montage
) .如果调用 superclass' equiv
方法,则无法获得像 Montage - Montage 这样的结果,因为每个传递的 Montage
都被隐式转换到 ComposantOrdi
。就像调用 superclass' 方法一样,结果的第二部分不能是 ComposantOrdi.
此外,如果您调用 superclass' 方法,
中的关键字this
Equivalence.equiv(this, c);
由 superclass 触发,这意味着即使对象是 Montage
它也会将自身传递为 ComposantOrdi
.
所以:调用superclass'方法只能产生输出ComposantOrdi - ComposantOrdi.
对于 Montage - Montage 这样的输出,您需要调用子 class' 方法 equiv
,这意味着:
- 您需要将
equiv
调用的接收者引用为Montage
(请参阅主体中的m2
,而不是m3
) - 你必须传入一个
Montage
对象
因为关键字 this
在 Montage
中触发,输出的第一部分必须是 Montage。第二部分也是 Montage 因为 Java 不会在不需要时隐式转换对象。这就是为什么选择以 Montages
作为参数的重载方法。
所以:调用sub class'方法只能产生输出Montage - Montage.
永远不会调用 Equivalence 的 equiv
方法的混合版本。
解释双重调度机制:
我认为双重派遣机制存在根本性的误解。所以让我解释一下。在介绍双分派机制之前,我将开始解释单分派。
单次发送: 单次分派意味着您调用对象的方法,执行的行为(方法调用的结果)取决于对象的具体类型。通常这称为多态性,使用抽象方法或方法覆盖来实现。
假设您有一个 class 系统,如下图所示。 Client
包含 Shapes
的列表。为了绘制所有这些,它循环遍历列表并在每个 Shape
上调用 paint
。当 class Triangle
在屏幕上绘制三角形时,Square
绘制正方形。通过不考虑 Shapes
是哪个具体子类型,执行的行为是在运行时确定的。
换句话说,调用 paint 方法的结果取决于 Shape
接口派生的具体子类型。 paint 方法的调用是 single 分派,因为只有 one 具体子类型决定运行时执行的行为。
DOUBLE DISPATCH:使用 double 调度机制,执行的行为在运行时受到 two 具体子类型的影响。像这样,您跨越了一个动态评估的行为矩阵。
如果根据下图修改class系统,客户端触发的绘制机制依赖于两个对象——Shape
和一个Painter
。客户端调用 paint
方法并注入它的 Painter
。然后 Shape
在 Painter
.
this
传递
像这样,Client
在不知道绘制什么颜色什么形状的情况下触发绘制机制。例如,如果它的画家是 GreenPainter
而 Shape
是 Triangle
,那么屏幕上会出现一个绿色三角形。
在此示例中,双重调度机制由 Shapes
' paint
方法的调用触发。
您应该看一下使用双重调度机制的访问者模式。