代码库中充斥着这样的代码:
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 类(及其子类)中,请实现 visitor pattern 。它将把 process 方法保留在 BaseRecord 类之外,但每次添加新的子类时,您都将被迫修改 Visitor 接口(interface)及其所有实现。因此,编译器将检查您是否忘记了开关中某个位置的情况。
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);
}
}
现在您只需为问题中描述的每个逻辑 block 实现 RecordVisitor:
RecordVisitor<Void> visitor = new ProcessRecordVisitor();
record.accept(visitor);
关于java - 悲伤的类型逻辑,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19877799/