java - "instanceof"运算符的这种使用是否被认为是糟糕的设计?

标签 java design-patterns instanceof object-oriented-analysis

在我的一个项目中,我有两个“数据传输对象”RecordType1 和 RecordType2,它们继承自 RecordType 的抽象类。

我希望两个 RecordType 对象都由“进程”方法中的同一 RecordProcessor 类处理。我的第一个想法是创建一个通用的流程方法,它委托(delegate)给两个特定的流程方法,如下所示:

public RecordType process(RecordType record){

    if (record instanceof RecordType1)
        return process((RecordType1) record);
    else if (record instanceof RecordType2)
        return process((RecordType2) record);

    throw new IllegalArgumentException(record);
}

public RecordType1 process(RecordType1 record){
    // Specific processing for Record Type 1
}

public RecordType2 process(RecordType2 record){
    // Specific processing for Record Type 2
}

我读到 Scott Meyers 在 Effective C++ 中写了以下内容:

“任何时候你发现自己在写这样的代码‘如果对象是 T1 类型,那么做某事,如果它是 T2 类型,那么做其他事情,’打自己一巴掌。”

如果他是正确的,显然我应该扇自己耳光。我真的不明白这是多么糟糕的设计(当然,除非有人继承 RecordType 并添加 RecordType3 而不向处理它的通用“Process”方法添加另一行,从而创建 NPE),以及我能想到的替代方案涉及将特定处理逻辑首当其冲地放在 RecordType 类本身中,这对我来说真的没有多大意义,因为理论上我可以对这些记录执行许多不同类型的处理。

有人可以解释为什么这可能被认为是糟糕的设计,并提供某种替代方案,仍然将处理这些记录的责任交给“处理”类吗?

更新:

  • return null改为throw new IllegalArgumentException(record);
  • 澄清一下,一个简单的 RecordType.process() 方法不够用的原因有以下三个:首先,处理与 RecordType 相去甚远,不值得在 RecordType 子类中使用自己的方法。此外,理论上可以由不同的处理器执行大量不同类型的处理。最后,RecordType 被设计成一个简单的 DTO 类,其中定义了最少的状态更改方法。

最佳答案

Visitor在这种情况下通常使用模式。虽然代码有点复杂,但在添加一个新的 RecordType 子类后,您必须在任何地方实现逻辑,否则将无法编译。 instanceof 到处都是,很容易漏掉一两个地方。

例子:

public abstract class RecordType {
    public abstract <T> T accept(RecordTypeVisitor<T> visitor);
}

public interface RecordTypeVisitor<T> {
    T visitOne(RecordType1 recordType);
    T visitTwo(RecordType2 recordType);
}

public class RecordType1 extends RecordType {
    public <T> T accept(RecordTypeVisitor<T> visitor) {
        return visitor.visitOne(this);
    }
}

public class RecordType2 extends RecordType {
    public <T> T accept(RecordTypeVisitor<T> visitor) {
        return visitor.visitTwo(this);
    }
}

用法(注意泛型返回类型):

String result = record.accept(new RecordTypeVisitor<String>() {

    String visitOne(RecordType1 recordType) {
        //processing of RecordType1
        return "Jeden";
    }

    String visitTwo(RecordType2 recordType) {
        //processing of RecordType2
        return "Dwa";
    }

});

另外我建议抛出异常:

throw new IllegalArgumentException(record);

当没有找到任何类型时,而不是返回 null

关于java - "instanceof"运算符的这种使用是否被认为是糟糕的设计?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8841577/

相关文章:

java - 从 jar 文件执行 Flyway 迁移

javascript - 这是什么功能模式?如果有的话?

javascript - 构建真实世界的 AngularJS 应用程序,我应该如何在 html 中声明我的 Controller 。我需要在index.html中声明所有内容吗?

typescript - instanceof 检查接口(interface)

java - JFace Action 和 ImageDescriptor - 我想显示图像和文本

java - 数组比 ArrayLists 更有效?

java - 使用编译和正则表达式获取字符串中的所有匹配项

javascript - 以正确的方式使用 Backbone 集合将它们传递到 subview 中,然后再传递到模板引擎中

java - instanceof 在现代 JVM 实现中是如何实现的?

php - 在 PHP 中按类(instanceof)切换