我最近遇到了API的问题以及出现以下类型代码的实现:
API是一个抽象类:
public abstract class A {
public A sum(A a) {
System.out.println("A.sum(A) called");
return null;
}
}
实现是一个简单的类:
public class B extends A {
public B sum(B b) {
System.out.println("B.sum(B) called");
return null;
}
}
说到使用它我写道:
public class Main {
public static void main(String args[]) {
B b = new B();
A basa = new B();
b.sum(b);
basa.sum(b);
basa.sum(basa);
}
}
结果是:
% java Main
B.sum(B) called
A.sum(A) called
A.sum(A) called
我知道B的总和不会覆盖A的总和,因为它的签名是不同的,但是我想为有效类型B的对象提供有效的总和实现。我认为这样的设计是非常经典的并且现在想要我应该如何设计我的API和实现,以便它有效。
当然,我可以在类中提供sum(A a)并在调用sum(B)或super之前检查b是否是instanceOf B,但我认为出于效率原因而避免使用instanceOf(如果它效率低下,作为我的“抽象”实现可能效率更低。
答案 0 :(得分:3)
由于B
个实例可以使用A
与myA.sum(myB)
个实例相加,因此您应该能够更改B
对sum
的定义,以便它 覆盖,除非sum
是一个占位符,并且不应该是可交换的。
更新:
如果这还不够,你可以开始使用泛型。我的意思是粗略的传递:
public abstract class A {
public <T extends A> T sum(T a) {
System.out.println("A.sum(A) called");
return null;
}
public static void main(String args[]) {
B b = new B();
b.sum(b);
A basa = new B();
basa.sum(b);
basa.sum(basa);
}
public static class B extends A {
@Override
public <T extends A> T sum(T b) {
System.out.println("B.sum(B) called");
return null;
}
}
}
@aioobe是正确的,普遍接受的解决方法是使用访客模式。我提供这些不太完整但不那么详细的替代品。
答案 1 :(得分:3)
instanceof
。根据您的需要,它可能是也可能不是过度杀伤力。它很灵活但很冗长。在下面的示例中,我从abstract
中删除了A
,以说明它如何与不同类型一起使用。
诀窍是,当要求对象访问访问者时,对象本身会在访问者中选择正确的accept
方法。 “instanceof”-check通过多态解决。 (我怀疑它比instanceof
更有效率。)
interface Visitor {
public A accept(A a);
public B accept(B b);
}
class A {
public A sum(A a) {
System.out.println("A.sum(A) called");
return null;
}
public A visit(Visitor sv) {
return sv.accept(this);
}
}
class B extends A {
public B sum(B b) {
System.out.println("B.sum(B) called");
return null;
}
public B visit(Visitor sv) {
return sv.accept(this);
}
}
public class Test {
public static void main(String[] args) {
A a = new A();
B b = new B();
A basa = new B();
a.visit(new SumVisitor(b)); // a.sum(b);
b.visit(new SumVisitor(b)); // b.sum(b);
basa.visit(new SumVisitor(b)); // basa.sum(b);
basa.visit(new SumVisitor(basa)); // basa.sum(basa);
}
static class SumVisitor implements Visitor {
A arg;
SumVisitor(A arg) { this.arg = arg; }
public A accept(A a) { return a.sum(arg); }
public B accept(B b) { return b.sum(arg); }
}
}
<强>输出:强>
A.sum(A) called
B.sum(B) called
B.sum(B) called
B.sum(B) called
Disclamer;不久之前我写了一个访问者,所以如果我在这个(几乎未经测试的)代码片段中有任何错误,请纠正我。或者更好,自己编辑帖子并改进它:)
答案 2 :(得分:0)
那么,是什么让你认为instanceof
很慢?它在JDK的几个地方使用,他们希望为抽象类或接口的某些众所周知的实现提供“快速路径”。通常的建议适用于此:“测试,不要猜测。”