访问者模式(Visitor)
简介
访问者模式,表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。这种类型的设计模式属于行为型模式。根据模式,元素对象已接受访问者对象,这样访问者对象就可以处理元素对象上的操作。
书中实例
今天我们来讲最后一个设计模式,访问者模式。大鸟说,把你刚才念的那段话用控制台应用程序写下来,我们来看看这个模式是怎么用的。
访问者模式实现程序
//人类
abstract class Person
{
//接受
public abstract void Accept(Action visitor);
}
//男人类
class Man : Person
{
//得到结论或反应
public override void Accept(Action visitor)
{
visitor.GetManConclusion(this);
}
}
//女人类
class Woman : Person
{
//得到结论或反应
public override void Accept(Action visitor)
{
visitor.GetWomanConclusion(this);
}
}
//状态抽象类
abstract class Action
{
//得到男人结论或反应
public abstract void GetManConclusion(Man concreteElementA);
//得到女人结论或反应
public abstract void GetWomanConclusion(Woman concreteElementA);
}
//成功类
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 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 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 vistor)
{
foreach (Person e in elements)
{
e.Accept(vistor);
}
}
}
//客户端
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);
Marriage v4 = new Marriage();
o.Display(v4);
Console.Read();
}
}
组成类图
关系介绍
访问者类(Visitor)是具体访问者类(ConcreteVistor)的父类。访问者类和客户端是关联关系。元素类(Element)是具体元素类的父类(ConcreteElement)。对象结构(ObjectStructure)和元素类,客户端之间又都是关联关系。
访问者模式的构成
Visitor(访问者类):为该对象结构中具体元素类的每一个类声明一个Visit操作。
ConcreteVistor(具体访问者类):实现每个由Visitor声明的操作。每个操作实现算法的一部分而该算法片断乃是对应于结构中的对象的类。
Element(元素类):定义了一个Accept操作,它以一个访问者为参数。
ConcreteElement(具体元素类):具体元素,实现Accept操作
ObjectStructure(对象结构):能枚举它的元素,可以提供一个高层的接口以允许访问者访问它的元素。
访问者模式的优缺点
优:1、符合单一职责原则。
2、优秀的扩展性。
3、灵活性。
缺:1、具体元素对访问者公布细节,违反了迪米特原则。
2、具体元素变更比较困难。
3、违反了依赖倒置原则,依赖了具体类,没有依赖抽象。
使用场景
1、对象结构中对象对应的类很少改变,但经常需要在此对象结构上定义新的操作。
2、需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而需要避免让这些操作"污染"这些对象的类,也不希望在增加新操作时修改这些类。