这种“实例”运算符的使用是否被视为不良设计?

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

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

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)在《有效C++》中写道:

“每当你发现自己在写代码时,'如果对象是T1类型,那就做点什么,但如果它是T2类型,那就做点别的事情,'打自己一巴掌。

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

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

更新:

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

答案 1

在这种情况下,通常使用访客模式。虽然代码有点复杂,但是在添加新的子类之后,你必须在任何地方实现逻辑,否则它不会编译。到处都是,很容易错过一两个地方。RecordTypeinstanceof

例:

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


答案 2

我的建议:

public RecordType process(RecordType record){
    return record.process();
}

public class RecordType
{
    public RecordType process()
    {
        return null;
    }
}

public class RecordType1 extends RecordType
{
    @Override
    public RecordType process()
    {
        ...
    }
}

public class RecordType2 extends RecordType
{
    @Override
    public RecordType process()
    {
        ...
    }
}

如果您需要执行的代码与模型不应该知道的内容(如UI)耦合,那么您将需要使用一种双重调度或访问者模式。

http://en.wikipedia.org/wiki/Double_dispatch


推荐