先说我的理解,访问者模式有2个参与者,一个访问者,一个被访问者。访问者是一组操作的集合,对他所知的被访问者进行操作。
访问者模式有2个重点,1 已知被访问者,就是说访问者只能访问有限的对象,如果所访问的对象增加了,那么就要修改访问者了,2 被访问者必须有个统一的被访问接口。
看GOF画的结构图,Visitor类就是访问者,Visitor类拥有几个方法是固定的,不同的方法访问不同的被访问者,我说的一个重点就是在这里体现,如果不幸有第三个对象需要访问,那么就只能修改Visitor类了,李建忠老师在视频里也说这是访问者模式的缺陷。而Element类就是被访问者了,它只有一个方法,接受Visitor类型参数的Accept方法,也就是所有被访问者统一的被访问接口,当然,实际上它还有自己的其他方法。
接着看,问题来了,这个ObjectStructure干什么的?GOF原图上干干净净的,李老师的视频也没提它,我就找了Terrylee版的C#设计模式来看,Terrylee对ObjectStructure的描述是一个统一调用被访问者的容器,语言不好描述,贴原码如下:
// "ObjectStructure"
class ObjectStructure
{
private ArrayList elements = new ArrayList();
public void Attach(Element element)
{
elements.Add(element);
}
public void Detach(Element element)
{
elements.Remove(element);
}
public void Accept(Visitor visitor)
{
foreach (Element e in elements)
{
e.Accept(visitor);
}
}
}
class ObjectStructure
{
private ArrayList elements = new ArrayList();
public void Attach(Element element)
{
elements.Add(element);
}
public void Detach(Element element)
{
elements.Remove(element);
}
public void Accept(Visitor visitor)
{
foreach (Element e in elements)
{
e.Accept(visitor);
}
}
}
个人觉得,这样理解恐怕不是很正确,我觉得这个ObjectStructure应该是一个相当自由的类,Visitor模式的变化就体现在这里,就是说如果增加了新的行为(给Visitor增加了新的子类),那么就应当在这里调用,而调用的方式不应当是这样固定的,应该是自由组合的。
//客户程序,变,如果增加新的Visitor,可以在这里体现
public class ObjectStructure
{
public void Process()
{
//访问者总数是不固定的,而使用也是需要则生成,不需要不生成
//在一个类里,不一定都用到,也可能不会只用一个
ConcreteVisitorA va = new ConcreteVisitorA();
ConcreteVisitorB vb = new ConcreteVisitorB();
//被访问者总数是固定的,总是这些
//在一个类里,不一定都用到,也可能不会只用一个
ConcreteElementA ca = new ConcreteElementA();
ConcreteElementB cb = new ConcreteElementB();
//对于放问者和被访问者的组合,应当是自由的,任意组合的
ca.Accept(va);
cb.Accept(va);
//
ca.Accept(vb);
cb.Accept(vb);
//
}
}
public class ObjectStructure
{
public void Process()
{
//访问者总数是不固定的,而使用也是需要则生成,不需要不生成
//在一个类里,不一定都用到,也可能不会只用一个
ConcreteVisitorA va = new ConcreteVisitorA();
ConcreteVisitorB vb = new ConcreteVisitorB();
//被访问者总数是固定的,总是这些
//在一个类里,不一定都用到,也可能不会只用一个
ConcreteElementA ca = new ConcreteElementA();
ConcreteElementB cb = new ConcreteElementB();
//对于放问者和被访问者的组合,应当是自由的,任意组合的
ca.Accept(va);
cb.Accept(va);
//
ca.Accept(vb);
cb.Accept(vb);
//
}
}
正是因为这个ObjectStructure这么自由,所以GOF的图中没有给出任何相关结构,呵呵,胡乱猜想,大家别笑。