【问题标题】:Polymorphic uncurried method calls (adhoc polymorphism) in JavaJava中的多态非curried方法调用(即席多态)
【发布时间】:2015-11-01 13:13:38
【问题描述】:

让我从一个例子开始。

假设我有一个抽象的Vehicle 类。

public abstract class Vehicle {

    public Vehicle() {}

    public abstract void ride();

}

以及继承自这个抽象类的类CarBicycle

public class Car extends Vehicle {

    public Car() {}

    @Override
    public void ride() {
        System.out.println("Riding the car.");
    }

}

public class Bicycle extends Vehicle {

    public Bicycle() {}

    @Override
    public void ride() {
        System.out.println("Riding the bicycle.");
    }

}

当我将ride() 方法应用于类型为Vehicle 的对象(其实际类型只能在运行时确定)时,JVM 将应用ride() 的正确版本。

也就是说,在v.ride() 类型的柯里化方法调用中,多态以预期的方式工作。

但是,如果我有一个只接受 Vehicle 子类型作为参数的方法形式的外部实现,该怎么办?那么,如果我有 repair(Bicycle b)repair(Car c) 方法怎么办? uncurried 多态方法调用repair(v) 将不起作用。

例子:

import java.util.ArrayList;
import java.util.List;

public class Main {

private static void playWithVehicle() {
    List<Vehicle> garage = new ArrayList<Vehicle>();
    garage.add(new Car());
    garage.add(new Car());
    garage.add(new Bicycle());
    garage.forEach((v) -> v.ride()); // Works.
    garage.forEach((v) -> {
        /* This would be nice to have.
        repair(v.castToRuntimeType());
        */

        // This is an ugly solution, but the obvious way I can think of.
        switch (v.getClass().getName()) {
        case "Bicycle":
            repair((Bicycle) v);
            break;
        case "Car":
            repair((Car) v);
            break;

        default:
            break;
        }
    });
}

private static void repair(Bicycle b) {
    System.out.println("Repairing the bicycle.");
}

private static void repair(Car c) {
    System.out.println("Repairing the car.");
}

public static void main(String[] args) {
    playWithVehicle();
}

}

我必须检查班级名称和向下转换。有没有更好的解决方案?


编辑:我的实际目的是我正在遍历一个抽象语法树,我碰巧注意到我想要双重调度。

Ast 是一个抽象类,AssignMethodCallReturnStmt 等实际 AST 节点从该类继承。 bodyAsts 的多态列表。

代码sn-p:

List<Ast> body;

body.parallelStream().forEach((ast) -> {
    // This one won't work.
    visit(ast);
    // This one will work.
    if (ast instanceof Assign) {
        visit((Assign) ast);
    } else if (ast instance of MethodCall) {
        visit((MethodCall) ast);
    } else if (ast instance of ReturnStmt) {
        visit((ReturnStmt) ast);
    }
    // etc. for other AST nodes
});

private void visit(Assign ast) {

}

private void visit(MethodCall ast) {

}

private void visit(ReturnStmt ast) {

}

我实现双重调度的唯一可能性是检查类并向下转换或正确实现访问者模式,对吗?

【问题讨论】:

  • 无论如何,不​​要开启类名。如果你有一个MountainBicycleBicycle 的子类怎么办?
  • 你是对的!我没有想到这一点。那么,这将变成很多ifelse if 形式的if(Bicycle.class.isAssignableFrom(v.getClass())) 语句。
  • 你的意思是if v instanceof Bicycle...
  • 啊,当然!我最初认为子类不会成为instanceof 的一部分。
  • 无论如何,关于你的实际问题,我怀疑你能否得到一个好的专家答案,因为通常这种情况的解决方案取决于实际的实际用例,而不是像“玩具类” Vehicle,Car,Bicycle,或者除了打印什么都不做的玩具方法。如果您发布一个现实世界的问题,它会更容易回答(尽管即使那样它最终也可能只是“基于意见”)。

标签: java polymorphism overloading double-dispatch adhoc-polymorphism


【解决方案1】:

答案:Java中没有多重分派,可以通过instanceof或访问者模式来模拟。

请看这里: Java method overloading + double dispatch

参见此处:https://en.wikipedia.org/wiki/Multiple_dispatch#Examples_of_emulating_multiple_dispatch

顺便说一句,这完全可以在 C# 中使用 dynamic 调用:How to build double dispatch using extensions

这在许多编译为 JVM 字节码的语言中也是可能的,例如提到了 Groovy。

【讨论】:

    猜你喜欢
    • 2015-07-14
    • 1970-01-01
    • 2016-03-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-03
    相关资源
    最近更新 更多