介绍
访问者模式(Visitor):表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。
结构图
角色
Visitor抽象访问者
抽象类或者接口,声明访问者可以访问哪些元素,具体到程序中就是visit方法的参数定义哪些对象是可以被访问的
ConcreteVisitor具体访问者
它影响访问者到一个类后该怎么干,要做什么事情
Element抽象元素
接口或者抽象类,声明接收哪一类访问者访问,程序上是通过accept方法中的参数来定义的
ConcreTElement具体元素
实现accept方法,通常是visitor.vist(this),基本上都形成了一种模式了。
ObjectStruturejiegou对象
元素生产者,一般容纳在多个不同类。不同接口的容器,如List、Set、Mapdeng,在项目中,一般很少抽象出这个角色
基本代码
Visitor类,为该对象结构中ConcreteElement中的每一个类声明一个Visit操作
abstract class Visitor
{
public abstract void VisitConcreteElementA(ConcreteElementA concreteElementA);
public abstract void VisitConcreteElementB(ConcreteElementB concreteElementB);
}
ConcreteVisitor1和ConcreteVisitor2类,具体访问者,实现每个由Visitor声明的操作。每个才做实现算法的一部分,而该算法片断乃是对应于结构中对象的类
class ConcreteVisitor1 : Visitor
{
public override void VisitConcreteElementA(ConcreteElementA concreteElementA)
{
Console.WriteLine("{0} 被{1}访问",concreteElementA.GetType().Name,this.GetType().Name);
}
public override void VisitConcreteElementB(ConcreteElementB concreteElementB)
{
Console.WriteLine("{0} 被{1}访问", concreteElementB.GetType().Name, this.GetType().Name);
}
}
class ConcreteVisitor2 : Visitor
{
public override void VisitConcreteElementA(ConcreteElementA concreteElementA)
{
Console.WriteLine("{0}被{1}访问", concreteElementA.GetType().Name, this.GetType().Name);
}
public override void VisitConcreteElementB(ConcreteElementB concreteElementB)
{
Console.WriteLine("{0}被{1}访问", concreteElementB.GetType().Name, this.GetType().Name);
}
}
Element类,定义一个Accept操作,它以一个访问者为参数
abstract class Element
{
public abstract void Accept(Visitor visitor);
}
ConcreteElementA和ConcreteElementB类,具体元素,实现Accept操作。
class ConcreteElementA : Element
{
public override void Accept(Visitor visitor) //充分利用双分派技术,实现处理与数据结构的分离
{
visitor.VisitConcreteElementA(this);
}
public void OperationA()
{ }
}
class ConcreteElementB : Element
{
public override void Accept(Visitor visitor) //充分利用双分派技术,实现处理与数据结构的分离
{
visitor.VisitConcreteElementB(this);
}
public void OperationB()
{ }
}
ObjectStructure类,能枚举 它的元素,可以提供一个高层的接口以允许访问者访问它的元素
class ObjectStructure
{
private IList<Element> elements = new List<Element>();
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);
}
}
}
效果
例子
结构图
代码实现
'状态'的抽象类和'人'的抽象类
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 Amativeeness : 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 Marriage : 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);
}
}
女人
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.Remove(element);
}
//查看信息
public void Display(Action visitor)
{
foreach (Person e in elements)
{
e.Accept(visitor);
}
}
}
客户端代码
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);
//恋爱时反应
Amativeeness v3 = new Amativeeness();
o.Display(v3);
//结婚时反应
Marriage v4 = new Marriage();
o.Display(v4);
Console.Read();
}
效果显示
访问者模式优点:
1.符合单一职责原则2.优秀的扩展性
3.灵活性非常高
访问者模式缺点
1.具体元素对访问者公布细节2.具体元素变更比较困难
3.违背了依赖倒转原则
适用场景
一个对象结构包含很多类对象,它们有不同的接口,而你想对这些对象实施一些依赖于其具体类的操作,也就是说用迭代器模式已经不能胜任的情景需要对一个对象结构中的对象进行很多不同并且不相关的操作,而你想避免让这些操作“污染”这些对象的类。