acyclic visitor模式?

08-10-17 zjsong11
Robert C. Martin 提出这样一种模式——acyclic visitor模式,就是把visitor模式的功能矩阵改变成了acyclicvisitor模式的稀疏矩阵,解除了依赖环。
然而,我在实现这个模式时却遇到了困难。比如Martin在书中给出了一个例子的:假设你有一个Modem的层次结构。接口中有对所有调制解调器都能实现的通用方法。调制解调器有两个类型的厂商,分别为:HayesModem和ErnieModem,分别要为不同的操作系统提供驱动。
请注意,被访问(Modem)层次结构的基类依赖于访问层次结构(ModemVisitor)的基类,访问者层次结构的基类中对于被访问层次结构中的每个派生类都有一个对应的函数。因此,就有一个依赖环把所有被访问的派生类(所有的调制解调器)都绑定在一起。这样就很难实现对访问者结构的增量编译,并且也很难向被访问层次结构中增加新的派生类。如果我们只需要HayesModem和EmieModem两种调制解调器,很少去增加新的Modem派生类,那么visitor模式将会非常合适。
可以使用一个被称为acyclic visitor模式的变体来解决这个问题。如下代码示例:
public interface Modem {
public void dial(String pno);
public void hangup();
public void send(char c);
public char recv();
public void accept(ModemVisitor v);
}

public interface ModemVisitor {}

public interface HayesModemVisitor extends ModemVisitor{
public void visit(HayesModem m);
}

public interface ErnieModemVisitor extends ModemVisitor{
public void visit(ErnieModem m);
}

public class HayesModem implements Modem {
String configurationString=null;
public void accept(ModemVisitor v) {
try {
HayesModemVisitor hv=(HayesModemVisitor) v;
hv.visit(this);
}catch(ClassCastException e) {}
}
public void dial(String pno) {}
public void hangup() {}
public char recv() {return 0;}
public void send(char c) {}
}

public class ErnieModem implements Modem {
String configurationPattern=null;
public void accept(ModemVisitor v) {
try {
ErnieModemVisitor ev=(ErnieModemVisitor) v;
ev.visit(this);
}catch(ClassCastException e) {}
}
public void dial(String pno) {}
public void hangup() {}
public char recv() {return 0;}
public void send(char c) {}
}

public class UnixModemConfigurator implements ModemVisitor,HayesModemVisitor,
ErnieModemVisitor {

public void visit(HayesModem m) {
m.configurationString="&s1=4&D=3";
}

public void visit(ErnieModem m) {
m.configurationPattern="C is too slow";
}
}

public class TestModemVisitor extends TestCase {
public TestModemVisitor(String name) {
super(name);
}
private UnixModemConfigurator v;
private HayesModem h;
private ErnieModem e;

public void setUp() {
v=new UnixModemConfigurator();
h=new HayesModem();
e=new ErnieModem();
}
public void testHayesForUnix() {
h.accept(v);
assertEquals("&s1=4&D=3",h.configurationString);
}
public void testErnieForUnix() {
e.accept(v);
assertEquals("C is too slow",e.configurationPattern);
}
}
然而,在测试程序中出现“类型HayesModem中的方法accept(ModemVisitor)对于参数(UnixModemConfigurator)不适用”。
我认为既然UnixModemConfigurator实现了ModemVisitor接口,那么就应该适用在这个参数。

banq
2008-10-17 21:56
没有问题,我将你的程序亲自运行了一下。感谢你为大家分享了你的案例。

我个人认为acyclic visitor是当有新元素加进来时,不至于影响原来的结构。

[该贴被banq于2008-10-17 21:57修改过]

zjsong11
2008-10-18 14:10
谢谢banq老师!
后来发现没有错误。这是书中的一个例子,当有新的调制解调器(modem)加进来时,只需要新建一个访问它的接口,访问者(如UnixModemConfigurator)只需实现这个接口就行了,如果Ernie调制解调器不需配置在UNIX中,那么UnixModemConfigurator就不实现ErineModemVisitor接口。