目的是封装一些施加于某种数据结构元素之上的操作。一旦这些操作需要修改的话,接受这个操作的数据结构则可以保持不变。
问题提出
System.Collection命名空间下提供了大量集合操作对象。但大多数情况下处理的都是同类对象的聚集。换言之,在聚集上采取的操作都是一些针对同类型对象的同类操作。但是如果针对一个保存有不同类型对象的聚集采取某种操作该怎么办呢?
粗看上去,这似乎不是什么难题。可是如果需要针对一个包含不同类型元素的聚集采取某种操作,而操作的细节根据元素的类型不同而有所不同时,就会出现必须对元素类型做类型判断的条件转移语句。这个时候,使用访问者模式就是一个值得考虑的解决方案。
访问者模式
访问者模式适用于数据结构相对未定的系统,它把数据结构和作用于结构上的操作之间的耦合解脱开,使得操作集合可以相对*地演化。
数据结构的每一个节点都可以接受一个访问者的调用,此节点向访问者对象传入节点对象,而访问者对象则反过来执行节点对象的操作。这样的过程叫做"双重分派"。节点调用访问者,将它自己传入,访问者则将某算法针对此节点执行。
双重分派意味着施加于节点之上的操作是基于访问者和节点本身的数据类型,而不仅仅是其中的一者。
public abstract class Visitor
{
public abstract void VisitorOneElement(OneElement one);
public abstract void VisitorTwoElement(TwoElement Two);
}
public class ConcreteOneVisitor : Visitor
{
public override void VisitorOneElement(OneElement one)
{
Console.WriteLine("{0} visited by {1}",one, this);
}
public override void VisitorTwoElement(TwoElement Two)
{
Console.WriteLine("{0} visited by {1}", Two, this);
}
}
public class ConcreteTwoVisitor : Visitor
{
public override void VisitorOneElement(OneElement one)
{
Console.WriteLine("{0} visited by {1}", one, this);
}
public override void VisitorTwoElement(TwoElement Two)
{
Console.WriteLine("{0} visited by {1}", Two, this);
}
}
public abstract class Element
{
public abstract void Accept(Visitor visitor);
}
public class OneElement : Element
{
public override void Accept(Visitor visitor)
{
visitor.VisitorOneElement(this);
}
}
public class TwoElement : Element
{
public override void Accept(Visitor visitor)
{
visitor.VisitorTwoElement(this);
}
}
//通过该类ObjectStruct把Element和visitor串联
public class ObjectStruct
{
private ArrayList list = new ArrayList();
public void Attach(Element element)
{
list.Add(element);
}
public void Detach(Element element)
{
list.Remove(element);
}
//展示
public void ObjectAccept(Visitor visitor)
{
foreach (Element e in list)
{
e.Accept(visitor);
}
}
}
实现
ObjectStruct os = new ObjectStruct();
os.Attach(new OneElement());
os.Attach(new TwoElement());
ConcreteOneVisitor one = new ConcreteOneVisitor();
ConcreteTwoVisitor two = new ConcreteTwoVisitor();
os.ObjectAccept(one);
os.ObjectAccept(two);
注:本文引自http://www.cnblogs.com/pursuedream/articles/795051.html