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);
    .
    . // ~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/

相关文章:

javascript - 在 ajax get-method Javascript 中发送对象

java - 当框架最大化时,滚动 Pane 消失

java - 过滤仅具有相交数据的 ArrayList

java - 在数组中生成随机数

java - 无需编码将字符串转换为字节数组?

java - 在 Intellij 中添加 Maven 依赖

java - 如何在jqplot条形图中放置多个条形

java - 如何在 Java JDBC 中处理异常?

java - 如何使用 Apache POI 制作垂直文本单元格样式?

java - 如何在选项卡小部件中创建 2 个 ListView