【发布时间】:2012-01-12 20:08:17
【问题描述】:
在我的一个项目中,我有两个“数据传输对象”RecordType1 和 RecordType2,它们继承自 RecordType 的抽象类。
我希望两个 RecordType 对象都由“进程”方法中的同一 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
}
我读到 Scott Meyers 在 Effective C++ 中写了以下内容:
“任何时候你发现自己在编写“如果对象是 T1 类型,那么就做某事,但如果它是 T2 类型,那就做其他事情”形式的代码,打自己一巴掌。”
如果他是正确的,显然我应该扇自己耳光。我真的不明白这是多么糟糕的设计(当然,除非有人将 RecordType 子类化并添加 RecordType3 而不向处理它的通用“Process”方法添加另一行,从而创建 NPE),以及我能想到的替代方案涉及将特定处理逻辑首当其冲地放在 RecordType 类本身中,这对我来说真的没有多大意义,因为理论上我可以对这些记录执行许多不同类型的处理。
有人可以解释为什么这可能被认为是糟糕的设计,并提供某种替代方案,仍然将处理这些记录的责任交给“处理”类吗?
更新:
- 将
return null更改为throw new IllegalArgumentException(record); - 澄清一下,一个简单的 RecordType.process() 方法不够用的原因有以下三个:首先,处理与 RecordType 相去甚远,不值得在 RecordType 子类中使用自己的方法。此外,理论上可以由不同的处理器执行大量不同类型的处理。最后,RecordType 被设计成一个简单的 DTO 类,其中定义了最少的状态更改方法。
【问题讨论】:
-
通常,这是一个不好的迹象。但是我们需要了解您要做什么-从问题中并不清楚。一般来说,您的所有类型似乎都具有相同的功能,因此您可以使用接口
-
RecordType1 和 2 有什么区别?你能让他们遵守同一个界面吗?
-
你通常不想这样做,但如果你只看到一次表达的逻辑,也许你会接受它。如果你开始在多个地方看到相同的
if (a instanceof X)逻辑,那你就真的不得不给自己一巴掌了。 -
嗯,RecordType1 和 RecordType2 有共同的子类吗?
-
仅供参考,Scott Myers 引用的具体引用来自第 39 条“避免继承继承权” - 第一版的第 138 页。他特别指出,C++(大约 1992 年)没有 instanceof 机制是一件好事。
标签: java design-patterns instanceof object-oriented-analysis