dep*_*ner 28 java design-patterns instanceof object-oriented-analysis
在我的一个项目中,我有两个"数据传输对象"RecordType1和RecordType2,它们继承自RecordType的抽象类.
我希望两个RecordType对象在"process"方法中由同一个RecordProcessor类处理.我的第一个想法是创建一个通用的流程方法,该方法委托给两个特定的流程方法,如下所示:
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
}
Run Code Online (Sandbox Code Playgroud)
我读过Scott Meyers在Effective C++中写了以下内容:
"任何时候你发现你自己编写的形式的代码'如果对象是T1类型,那么做一些事情,但如果它是T2类型,那么做一些其他的事情,'打自己."
如果他是对的,显然我应该打自己.我真的没有看到这是多么糟糕的设计(除非当然有人将RecordType子类化并添加到RecordType3而不向处理它的通用"Process"方法添加另一行,从而创建一个NPE),以及我能想到的替代方案涉及将特定处理逻辑首当其冲地放在RecordType类本身中,这对我来说真的没有多大意义,因为理论上我可以对这些记录执行许多不同类型的处理.
有人可以解释为什么这可能被视为糟糕的设计并提供某种替代方案,仍然负责将这些记录处理到"处理"类?
更新:
return null
以throw new IllegalArgumentException(record);
Tom*_*icz 26
该访问者模式通常在这样的情况下使用.虽然代码有点复杂,但是在添加新的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);
}
}
Run Code Online (Sandbox Code Playgroud)
用法(注意泛型返回类型):
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";
}
});
Run Code Online (Sandbox Code Playgroud)
我还建议抛出异常:
throw new IllegalArgumentException(record);
Run Code Online (Sandbox Code Playgroud)
而不是在null
找不到任何类型时返回.