代码库充满了这样的代码:
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
方法。这种逻辑在任何地方都会重复,我想太多了,无法为每个方法添加一个方法并在类中重写。我怎样才能改善这个?
答案 0 :(得分:1)
访客模式和策略模式都可以在这里使用。 http://en.wikipedia.org/wiki/Strategy_pattern和http://en.wikipedia.org/wiki/Visitor_pattern
答案 1 :(得分:1)
第一种解决方案:良好的旧多态性。
只需向BaseRecord类添加一个抽象的process()
方法,并在每个子类中覆盖它。因此代码将成为:
BaseRecord record = ...;
record.process();
如果无法将process()
方法添加到BaseRecord类(及其子类)中,请实现visitor pattern。它会将进程方法留在BaseRecord类之外,但每次添加新的子类时,都会被迫修改Visitor接口及其所有实现。因此,编译器将检查您是否忘记了交换机中的案例。
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);
}
}
现在您只需为问题中描述的每个逻辑块实现RecordVisitor:
RecordVisitor<Void> visitor = new ProcessRecordVisitor();
record.accept(visitor);
答案 2 :(得分:0)
我认为这很有启发性:
package classplay;
public class ClassPlay
{
public void say(String msg) { System.out.println(msg); }
public static void main(String[] args)
{
ClassPlay cp = new ClassPlay();
cp.go();
}
public void go()
{
A someClass = new C();
say("calling process with double dispatch");
someClass.dueProcess(this);
say("now calling process directly");
process(someClass);
}
public void process(A a)
{
say("processing A");
a.id();
}
public void process(B b)
{
say("processing B");
b.id();
}
public void process(C c)
{
say("processing C");
c.id();
}
abstract class A
{
abstract public void id(); // { System.out.println("Class A"); }
public void dueProcess(ClassPlay cp) { cp.process(this); }
}
class B extends A
{
public void id() { System.out.println("Class B"); }
public void dueProcess(ClassPlay cp) { cp.process(this); }
}
class C extends A
{
public void id() { System.out.println("class C"); }
public void dueProcess(ClassPlay cp) { cp.process(this); }
}
}