设计模式系列漫谈之十三 - 访问者模式
有这么一则笑话:
话说有对一年轻夫妇生了一对双胞胎男孩。俩小子长得一模一样,还特别调皮。 平时一般都是妈妈照顾俩小子。可是有一天, 妈妈出差了,晚上爸爸给俩小子胎洗完澡,把他放到床上,催他们快睡觉,小宝就笑起来了:“哥哥都洗两次了,我都还没洗澡呢。”。爸爸:“还好不是喂饭” 。
访问者模式(Visitor)解决方案
访问者模式适用于数据结构相对稳定的系统(两个小孩、负责喂饭和洗澡),它把数据结构和作用于结构上的操作之间的耦合解脱开,使得操作集合可以相对自由地演化。数据结构的每一个节点都可以接受一个访问者的调用,此节点向访问者对象传入节点对象,而访问者对象则反过来执行节点对象的操作。这样的过程叫做"双重分派"。节点调用访问者,将它自己传入,访问者则将某算法针对此节点执行。
访问者模式涉及到抽象访问者角色、具体访问者角色、抽象节点角色、具体节点角色、结构对象角色以及客户端角色。
抽象访问者(Visitor)角色:声明了一个或者多个访问操作,形成所有的具体元素角色必须实现的接口。如Visitor类
具体访问者(ConcreteVisitor)角色:实现抽象访问者角色所声明的接口,也就是抽象访问者所声明的各个访问操作。 如Wash类、Feed类。
抽象节点(Element)角色:声明一个接受操作,接受一个访问者对象作为一个参量。如Child类。
具体节点(ConcreteElement)角色:实现了抽象元素所规定的接受操作。如Son类。
结构对象(ObiectStructure)角色:可以遍历结构中的所有元素;如ObiectStructure
Visitor类如下:
public abstract class Visitor
{
public abstract void Visitor(Son son);
}
Wash类如下:
{
public abstract void Visitor(Son son);
}
public class Wash:Visitor
{
public override void Visitor(Son son)
{
son.Washed=true;
}
}
Feed类如下:
{
public override void Visitor(Son son)
{
son.Washed=true;
}
}
public class Feed:Visitor
{
public override void Visitor(Son son)
{
son.Feeded=true;
}
}
Child类如下:
{
public override void Visitor(Son son)
{
son.Feeded=true;
}
}
public abstract class Child
{
public string Name;
public bool Washed=false;
public bool Feeded=false;
public Child(string name)
{
Name=name;
}
public abstract void Accept(Visitor visitor);
}
Son类如下:
{
public string Name;
public bool Washed=false;
public bool Feeded=false;
public Child(string name)
{
Name=name;
}
public abstract void Accept(Visitor visitor);
}
public class Son:Child
{
public Son(string name):base(name)
{
}
public override void Accept(Visitor visitor)
{
visitor.Visitor(this);
}
}
ObiectStructure类如下:
{
public Son(string name):base(name)
{
}
public override void Accept(Visitor visitor)
{
visitor.Visitor(this);
}
}
public class ObiectStructure
{
private List<Child> list=new List<Child>();
public void Add(Child ch)
{
list.Add(ch);
}
public void Remove(Child ch)
{
list.Remove(ch);
}
public void TakeCareofChildren(Visitor visitor)
{
foreach(Child ch in list)
{
ch.Accept(visitor);
}
}
}
客户端调用如下:
{
private List<Child> list=new List<Child>();
public void Add(Child ch)
{
list.Add(ch);
}
public void Remove(Child ch)
{
list.Remove(ch);
}
public void TakeCareofChildren(Visitor visitor)
{
foreach(Child ch in list)
{
ch.Accept(visitor);
}
}
}
public class Client
{
public static void Main()
{
ObjectStructure obj=new ObjectStructure();
obj.Add(new Son("小宝"));
obj.Add(new Son("大宝"));
Wash w=new Wash();
obj.TakeCareofChildren(w);
Feed f=new Feed();
obj.TakeCareofChildren(f);
}
}
{
public static void Main()
{
ObjectStructure obj=new ObjectStructure();
obj.Add(new Son("小宝"));
obj.Add(new Son("大宝"));
Wash w=new Wash();
obj.TakeCareofChildren(w);
Feed f=new Feed();
obj.TakeCareofChildren(f);
}
}