Head First设计模式之访问者模式
一、定义
定义:表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素类的前提下定义作用于这些元素的新操作。
访问者模式适用于数据结构相对稳定的系统, 它把数据结构和作用于数据结构之上的操作之间的耦合度降低,使得操作集合可以相对自由地改变。
数据结构的每一个节点都可以接受一个访问者的调用,此节点向访问者对象传入节点对象,而访问者对象则反过来执行节点对象的操作。这样的过程叫做“双重分派”。节点调用访问者,将它自己传入,访问者则将某算法针对此节点执行。
二、结构图
这里需要明确一点:访问者模式中具体访问者的数目和具体节点的数目没有任何关系。从访问者的结构图可以看出,访问者模式涉及以下几类角色。
- 抽象访问者角色(Vistor):声明一个活多个访问操作,使得所有具体访问者必须实现的接口。
- 具体访问者角色(ConcreteVistor):实现抽象访问者角色中所有声明的接口。
- 抽象节点角色(Element):声明一个接受操作,接受一个访问者对象作为参数。
- 具体节点角色(ConcreteElement):实现抽象元素所规定的接受操作。
- 结构对象角色(ObjectStructure):节点的容器,可以包含多个不同类或接口的容器。
三、适用场景
1、对象结构中对象对应的类很少改变,但经常需要在此对象结构上定义新的操作。
2、需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而需要避免让这些操作"污染"这些对象的类,也不希望在增加新操作时修改这些类。
四、优缺点
优点: 1、符合单一职责原则。 2、优秀的扩展性。 3、灵活性。
缺点: 1、具体元素对访问者公布细节,违反了迪米特原则。 2、具体元素变更比较困难。 3、违反了依赖倒置原则,依赖了具体类,没有依赖抽象。
五、实现
思路:商家定义了一个套餐A,为套餐A添加了土豆和花生,然后张三、李四才点了套餐A。
好处:不管多少人来,都是给他们的菜都是一样的
坏处:如果套餐A 突然加了一个菜 海带, 导致所有人都要来拿海带,所以变化是非常困难的。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace DesignPatterns.Visitor { class Program { static void Main(string[] args) { Food a = new Potato(); Food b = new Peanut(); var combo = new Combo(); combo.Add(a); combo.Add(b); Visitor charger = new Charger("张三"); Visitor workerOfPharmacy = new WorkerOfPharmacy("李四"); combo.Accpet(charger); Console.WriteLine(); combo.Accpet(workerOfPharmacy); } } /// <summary> /// 抽象访问者 /// </summary> public abstract class Visitor { protected string name { get; set; } public Visitor(string name) { this.name = name; } public abstract void visitor(Potato a); public abstract void visitor(Peanut b); } /// <summary> /// 具体访问者:张三 /// </summary> public class Charger : Visitor { public Charger(string name) : base(name) { } public override void visitor(Potato a) { Console.WriteLine("张三:" + this.name + " 取菜 " + a.GetName()); } public override void visitor(Peanut b) { Console.WriteLine("张三:" + this.name + " 取菜 " + b.GetName()); } } /// <summary> /// 具体访问者:李四 /// </summary> public class WorkerOfPharmacy : Visitor { public WorkerOfPharmacy(string name) : base(name) { } public override void visitor(Potato a) { Console.WriteLine("李四:" + this.name + " 取菜 " + a.GetName() ); } public override void visitor(Peanut b) { Console.WriteLine("李四:" + this.name + " 取菜 " + b.GetName()); } } /// <summary> /// 抽象元素:食物 /// </summary> public abstract class Food { protected string name { get; set; } public Food() { name = "我是食物"; } public string GetName() { return name; } public abstract void Accept(Visitor visitor); } /// <summary> /// 具体元素:土豆 /// </summary> public class Potato : Food { public Potato() { this.name = "土豆"; } public override void Accept(Visitor visitor) { visitor.visitor(this); } } /// <summary> /// 具体元素:花生 /// </summary> public class Peanut : Food { public Peanut() { this.name = "花生"; } public override void Accept(Visitor visitor) { visitor.visitor(this); } } /// <summary> /// 具体元素:套餐 /// </summary> public class Combo { private List<Food> list = new List<Food>(); public void Accpet(Visitor visitor) { foreach (var item in list) { item.Accept(visitor); } } public void Add(Food med) { list.Add(med); } public void Remove(Food med) { list.Remove(med); } } }
参考
http://blog.csdn.net/heyangyi_19940703/article/details/51374416
http://www.cnblogs.com/zhili/p/VistorPattern.html
http://www.cnblogs.com/JsonShare/p/7380772.html
欢迎阅读本系列文章:Head First设计模式之目录