初识
访问者模式(Visitor),表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。
访问者模式,是行为型设计模式之一。访问者模式是一种将数据操作与数据结构分离的设计模式,它可以算是 23 中设计模式中最复杂的一个,但它的使用频率并不是很高,大多数情况下,你并不需要使用访问者模式,但是当你一旦需要使用它时,那你就是需要使用它了。
访问者模式的基本想法是,软件系统中拥有一个由许多对象构成的、比较稳定的对象结构,这些对象的类都拥有一个 accept 方法用来接受访问者对象的访问。访问者是一个接口,它拥有一个 visit 方法,这个方法对访问到的对象结构中不同类型的元素做出不同的处理。在对象结构的一次访问过程中,我们遍历整个对象结构,对每一个元素都实施 accept 方法,在每一个元素的 accept 方法中会调用访问者的 visit 方法,从而使访问者得以处理对象结构的每一个元素,我们可以针对对象结构设计不同的访问者类来完成不同的操作,达到区别对待的效果。
结构
角色:
- Visitor类:为该对象结构中ConcreteElement的每一个类声明一个Visit操作
- ConcreteVisitor类:具体访问者,实现每个由Visitor声明的操作。每个操作实现算法的一部分,而该算法片段乃是对应于结构中对象的类
- Element类:定义一个Accept操作,它以一个访问者为参数
- ConcreteElementA类:具体元素,实现Accept操作
- ObjectStructure类:能枚举它的元素,可以提供一个高层的接口以允许访问者访问它的元素
应用
男人和女人的对比。
class Program
{
static void Main(string[] args)
{
ObjectStructure o = new ObjectStructure();
o.Attach(new Man());
o.Attach(new Woman());
Success v1 = new Success();
o.Display(v1);
Failing v2 = new Failing();
o.Display(v2);
Amativeness v3 = new Amativeness();
o.Display(v3);
Console.Read();
}
}
abstract class Action//抽象动作类
{
public abstract void GetManConclusion(Man concreteElementA);
public abstract void GetWomanConclusion(Woman concreteElementB);
}
abstract class Person//抽象人类
{
public abstract void Accept(Action visitor);//接受
}
class Success:Action//成功类
{
public override void GetManConclusion(Man concreteElementA)
{
Console.WriteLine("{0} {1}时,背后多半有一个伟大的女人",concreteElementA.GetType().Name,this.GetType().Name);
}
public override void GetWomanConclusion(Woman concreteElementB)
{
Console.WriteLine("{0} {1}时,背后大多有一个不成功的男人", concreteElementB.GetType().Name, this.GetType().Name);
}
}
class Failing :Action//失败类
{
public override void GetManConclusion(Man concreteElementA)
{
Console.WriteLine("{0} {1}时,闷头喝酒,谁也不用劝", concreteElementA.GetType().Name, this.GetType().Name);
}
public override void GetWomanConclusion(Woman concreteElementB)
{
Console.WriteLine("{0} {1}时,眼泪汪汪,谁也劝不了", concreteElementB.GetType().Name, this.GetType().Name);
}
}
class Amativeness:Action//恋爱类
{
public override void GetManConclusion(Man concreteElementA)
{
Console.WriteLine("{0} {1}时,凡事不懂也要装懂", concreteElementA.GetType().Name, this.GetType().Name);
}
public override void GetWomanConclusion(Woman concreteElementB)
{
Console.WriteLine("{0} {1}时,遇事懂也要装作不懂", concreteElementB.GetType().Name, this.GetType().Name);
}
}
class Man:Person//男人类
{
public override void Accept(Action visitor)
{
visitor.GetManConclusion(this);//首先,在客户端程序中将具体状态作为参数传递给“男人”类完成一次分派;然后“男人”类调用作为参数的“具体状态”中的方法“反应”,同时将自己作为(this)作为参数传递进去,这就完成了第二次分派。
}
}
class Woman : Person//女人类
{
public override void Accept(Action visitor)
{
visitor.GetWomanConclusion(this);
}
}
class ObjectStructure//对象结构类
{
private IList<Person> elements = new List<Person>();
public void Attach(Person element)
{
elements.Add(element);
}
public void Detach(Person element)
{
elements.Add(element);
}
public void Display(Action visitor)
{
foreach (Person e in elements)//遍历方法
{
e.Accept(visitor);
}
}
}
优点
-
增加新的访问操作十分方便,因为增加新的操作就意味着增加一个新的访问者。 => 符合开闭原则
-
将有关元素对象的访问行为集中到一个访问者对象中,而不是分散在一个个的元素类中,类的职责更加清晰 => 符合单一职责原则
缺点
- 使增加新的数据结构变得困难
适用情景
- 适用于数据结构相对稳定的系统,又有易于变化的算法。因为访问者模式使得算法操作的增加变得容易