一、引言
上篇博客中与大家分享了责任链模式,责任链模式主要应用于系统中某个功能需要多个参与者完成的场景,今天将分享我对访问者模式的理解
二、访问者模式
定义:表示一个作用于某对象结构中的各元素的操作,它使你可以在不改变各元素类的前提下定义作用于这些元素的新操作
下面是访问者模式结构图:
场景:人有男女两个类别,两者在成功或失败时外界的评价是不一样的
下面是代码demo

abstract class Person { protected string action; public string Action { get { return action; } set { action = value; } } public abstract void GetConclution(); } class Man : Person { public override void GetConclution() { if (action == "成功") { Console.WriteLine($"{this.GetType().Name}{action}背后都有一个成功的女人"); } else if (action == "失败") { Console.WriteLine($"{this.GetType().Name}{action}闷头喝酒,谁也不用劝"); } } } class Woman : Person { public override void GetConclution() { if (action == "成功") { Console.WriteLine($"{this.GetType().Name}{action}背后都有一个不成功的男人"); } else if (action == "失败") { Console.WriteLine($"{this.GetType().Name}{action}眼泪汪汪,谁也劝不了"); } } } class Program { static void Main(string[] args) { List<Person> lstPerson = new List<Person>(); Man manA = new Man { Action = "成功" }; lstPerson.Add(manA); Man manB = new Man { Action = "失败" }; lstPerson.Add(manB); Woman womanA = new Woman(); womanA.Action = "成功"; lstPerson.Add(womanA); Woman womanB = new Woman(); womanB.Action = "失败"; lstPerson.Add(womanB); foreach (Person person in lstPerson) { person.GetConclution(); } Console.Read(); } }
分析:该示例是应该是最容易想到的实现吧,但是当有新的操作作用于男人、女人时就不得不修改man类或者woman类了,违背了“开-闭”原则,我们认为不是好的设计。
下面是大话设计模式模式中例子

//抽象访问者类, 作用于对象结构各个元素的类 abstract class Vistor { public abstract void VisitConcreteElementA(ConcreteElementA concreteElementA); public abstract void VisitConcreteElementB(ConcreteElementB concreteElementB); } //抽象元素类 以访问者为参数 abstract class Element { public abstract void Accept(Vistor vistor); } class ConcreteVistorA : Vistor { public override void VisitConcreteElementA(ConcreteElementA concreteElementA) { Console.WriteLine($"{concreteElementA.GetType().Name}被访{this.GetType().Name}问"); } public override void VisitConcreteElementB(ConcreteElementB concreteElementB) { Console.WriteLine($"{concreteElementB.GetType().Name}被{this.GetType().Name}访问"); } } class ConcreteVistorB : Vistor { public override void VisitConcreteElementA(ConcreteElementA concreteElementA) { Console.WriteLine($"{concreteElementA.GetType().Name}被{this.GetType().Name}访问"); } public override void VisitConcreteElementB(ConcreteElementB concreteElementB) { Console.WriteLine($"{concreteElementB.GetType().Name}被{this.GetType().Name}访问"); } } class ConcreteElementA : Element { public override void Accept(Vistor vistor) { vistor.VisitConcreteElementA(this); } public void OperationA() { Console.WriteLine($"{this.GetType().Name}"); } } class ConcreteElementB:Element { public override void Accept(Vistor vistor) { vistor.VisitConcreteElementB(this); } public void OperationB() { Console.WriteLine($"{this.GetType().Name}"); } } //对象结构类 ,允许访问者访问它的元素 class ObjectStructure { public IList<Element> elements = new List<Element>(); public void Add(Element element) { elements.Add(element); } public void Remove(Element element) { elements.Remove(element); } public void Dispay(Vistor vistor) { foreach (Element element in elements) { element.Accept(vistor); } } } class Program { static void Main(string[] args) { //定义对象结构 ObjectStructure objectStructure = new ObjectStructure(); objectStructure.Add(new ConcreteElementA()); objectStructure.Add(new ConcreteElementB()); //创建访问者 ConcreteVistorA concreteVistorA = new ConcreteVistorA(); ConcreteVistorB concreteVistorB = new ConcreteVistorB(); //作用于对象结构各个元素 objectStructure.Dispay(concreteVistorA); objectStructure.Dispay(concreteVistorB); Console.Read(); } }
分析:上述示例中 将处理从数据结构中分离出来,这时新增加操作时增加一个新的访问者就可以了
优点:
1.能够在不修改对象结构中元素的前提下,为对象结构中元素增加新的功能
2.访问者模式使得有关的行为操作集中到一个访问者对象中,而不是分散到一个个元素类中
3.可以通过访问者定义整个结构中的通用功能,提高复用性
缺点:
1.增加新的元素类比较困难,每增加一个新的元素类意味着抽象访问者类要增加一个新的抽象操作,并在每一个具体的访问者类中增加操作
适用场景:
1.系统有比较稳定的数据结构,而又有易于变化的算法时,此时可以考虑使用访问者模式
2.如果一组类中存在相似的操作,为了避免大量重复的代码,可以考虑封装到访问者类中
3.如果一个对象存在着与本身对象不相关,或者关系比较弱的操作时,为了避免污染这个对象,可以考虑把这些操作封装到访问者类中
参考:
大话设计模式
http://www.cnblogs.com/zhili/p/VistorPattern.html;
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接。