意图
- 表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作;
——《设计模式》GoF
适用性
-
一个对象结构包含很多对象,它们有不同的接口,而你想对这些对象呢实施一些依赖于其具体类的操作。
-
需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而你想避免让这些操作“污染”这些对象的类。
-
定义对象结构的类很少改变,但经常需要在此结构上定义新的操作。
结构
参与者
-
Visitor
-
为该对象结构中的ConcreteElement的每一个类声明一个操作。该操作的名字和特征标识了发送visit请求给该访问者的那个类。
-
ConcreteVisitor
-
实现每个Visitor声明的操作。每个操作实现本算法的一部分,而该算法片断乃是对应于结构中对象的类。
-
Element
-
定义一个Accept操作,它以一个访问者作为参数。
-
ConcreteElement
-
实现Accept操作,该操作以一个访问者为参数
-
ObjectStructure
-
能枚举它的元素
-
可以提供一个高层的接口以允许该访问者访问它的元素
-
可以是一个复合或是一个集合。
协作
-
一个使用Visitor模式的客户必须创建一个ConcreteVisitor对象,然后遍历该对象结构并用该访问者访问每一个元素
-
当一个元素被访问时,它调用对应于它的类的visitor操作。如果必要该元素将自身作为这个操作的一个参数以便该访问者访问它的状态。
效果
-
访问者模式使得易于增加新的操作
-
访问者集中相关的操作而分离无关的操作
-
增加新的ConcreteElement类很困难
-
通过类层次进行访问
-
累积状态
-
破坏封装
实现
-
双分派(double dispatch)
-
谁负责遍历对象结构
代码
class VisitorStructure
{
public void Test()
{
Element elementA = new ConcreteElementA();
Element elementB = new ConcreteElementB();
Visitor visitorA = new ConcreteVisitorA();
Visitor visitorB = new ConcreteVisitorB();
elementA.Accept(visitorA);
elementA.Accept(visitorB);
elementB.Accept(visitorB);
elementB.Accept(visitorA);
}
}
abstract class Visitor
{
public abstract void VisitConcreteElementA(ConcreteElementA concreteElementA);
public abstract void VisitConcreteElementB(ConcreteElementB concreteElementB);
}
class ConcreteVisitorA : Visitor
{
public override void VisitConcreteElementA(ConcreteElementA concreteElementA)
{
concreteElementA.Operation();
}
public override void VisitConcreteElementB(ConcreteElementB concreteElementB)
{
concreteElementB.Operation();
}
}
class ConcreteVisitorB : Visitor
{
public override void VisitConcreteElementA(ConcreteElementA concreteElementA)
{
concreteElementA.Operation();
}
public override void VisitConcreteElementB(ConcreteElementB concreteElementB)
{
concreteElementB.Operation();
}
}
abstract class Element
{
public abstract void Accept(Visitor visitor);
public void Operation()
{
Console.WriteLine(this.GetType().Name);
}
}
class ConcreteElementA:Element
{
public override void Accept(Visitor visitor)
{
visitor.VisitConcreteElementA(this);
}
}
class ConcreteElementB : Element
{
public override void Accept(Visitor visitor)
{
visitor.VisitConcreteElementB(this);
}
}