Java 关于类型的悲哀逻辑
代码库中到处都是这样的代码:Java 关于类型的悲哀逻辑,java,Java,代码库中到处都是这样的代码: BaseRecord record = // some BaseRecord switch(record.source()) { case FOO: return process((FooRecord)record); case BAR: return process((BarRecord)record); case QUUX: return process((QuuxRecord)record
BaseRecord record = // some BaseRecord
switch(record.source()) {
case FOO:
return process((FooRecord)record);
case BAR:
return process((BarRecord)record);
case QUUX:
return process((QuuxRecord)record);
.
. // ~25 more cases
.
}
然后
private SomeClass process(BarRecord record) { }
private SomeClass process(FooRecord record) { }
private SomeClass process(QuuxRecord record) { }
这让我非常难过。然后,每次从
BaseRecord
派生一个新类时,我们都必须在代码库中查找更新这些case语句并添加新的process
方法。这种逻辑到处重复,我认为太多了,无法为每个类添加方法并在类中重写。如何改进这一点?访客模式和策略模式都可以在这里使用。第一个解决方案:好的多态性
只需向BaseRecord类添加一个抽象的process()
方法,并在每个子类中重写它。因此,该守则将成为:
BaseRecord record = ...;
record.process();
如果无法将process()
方法添加到BaseRecord类(及其子类)中,则实现。它将把process方法保留在BaseRecord类之外,但是每次添加新的子类时,都将被迫修改Visitor接口及其所有实现。因此,编译器将为您检查是否忘记了开关中的一个case
public interface RecordVisitor<T> {
T visitFoo(FooRecord foo);
T visitBar(BarRecord foo);
...
}
public abstract class BaseRecord {
public abstract <T> T accept(RecordVisitor<T> visitor);
}
public class FooRecord extends BaseRecord {
@Override
public <T> T accept(RecordVisitor<T> visitor) {
return visitor.visitFoo(this);
}
}
public class BarRecord extends BaseRecord {
@Override
public <T> T accept(RecordVisitor<T> visitor) {
return visitor.visitBar(this);
}
}
公共接口记录访问者{
T visitFoo(foo记录foo);
T visitBar(BarRecord foo);
...
}
公共抽象类基记录{
不接受公开摘要(记录访问者);
}
公共类FooRecord扩展了BaseRecord{
@凌驾
公众不接受(记录访客){
return visitor.visitFoo(这个);
}
}
公共类BarRecord扩展BaseRecord{
@凌驾
公众不接受(记录访客){
回访访客。访客栏(本);
}
}
现在,您只需为问题中描述的每个逻辑块实现RecordVisitor:
RecordVisitor<Void> visitor = new ProcessRecordVisitor();
record.accept(visitor);
RecordVisitor=newprocessrecordvisitor();
记录。接受(访客);
我认为这很有启发性:
package classplay;
public class ClassPlay
{
public void say(String msg) { System.out.println(msg); }
public static void main(String[] args)
{
ClassPlay cp = new ClassPlay();
cp.go();
}
public void go()
{
A someClass = new C();
say("calling process with double dispatch");
someClass.dueProcess(this);
say("now calling process directly");
process(someClass);
}
public void process(A a)
{
say("processing A");
a.id();
}
public void process(B b)
{
say("processing B");
b.id();
}
public void process(C c)
{
say("processing C");
c.id();
}
abstract class A
{
abstract public void id(); // { System.out.println("Class A"); }
public void dueProcess(ClassPlay cp) { cp.process(this); }
}
class B extends A
{
public void id() { System.out.println("Class B"); }
public void dueProcess(ClassPlay cp) { cp.process(this); }
}
class C extends A
{
public void id() { System.out.println("class C"); }
public void dueProcess(ClassPlay cp) { cp.process(this); }
}
}
我猜你要找的是泛型。事实上:泛型加接口事实上,多态性,或者访问者模式正如我在我的问题中解释的(很糟糕),有很多这样的逻辑块的实例(例如,
switch(record.source()){case-FOO:return X((FooRecord)FOO);case-BAR:return X(BarRecord)record);}
和X(FooRecord记录){}X(BarRecord记录){}
),但有许多不同的X
方法)。仅仅将每个X
添加到基类并重写似乎不是一个好的解决方案。我正在寻找更好的解决方案。这就是为什么我的答案是:如果不能在BaseRecord类中添加process()方法,那么就实现访问者模式。每个逻辑块将转换为一个不同的访问者实现。BaseRecord类只需要一个附加方法,供每个访问者使用:accept(RecordVisitor)
非常感谢。我终于明白了。