表示一個作用於某對象結構中的各元素的操作。它使你可以在不改變各元素類的前提下定義作用於這些元素的新操作。
1.Visitor 抽象訪問者角色,為該對象結構中具體元素角色聲明一個訪問操作接口。該操作接口的名字和參數標識了發送訪問請求給具體訪問者的具體元素角色,這樣訪問者就可以通過該元素角色的特定接口直接訪問它。
2.ConcreteVisitor.具體訪問者角色,實現Visitor聲明的接口。
3.Element 定義一個接受訪問操作(accept()),它以一個訪問者(Visitor)作為參數。
4.ConcreteElement 具體元素,實現了抽象元素(Element)所定義的接受操作接口。
5.ObjectStructure 結構對象角色,這是使用訪問者模式必備的角色。它具備以下特性:能枚舉它的元素;可以提供一個高層接口以允許訪問者訪問它的元素;如有需要,可以設計成一個復合對象或者一個聚集(如一個列表或無序集合)。
在生活中,我們要去醫院看病,當我們掛號找到主治醫生的醫生看完病以後,會給你開一張藥單,這個時候你需要先去付費,由劃價醫生收取藥費,然後你拿著付費單再去找抓藥師抓藥。傳統上我們也許會,寫一個劃價師類,裡面根據藥的名稱做判斷收取多少費用;寫一個抓藥師根據藥單上面名稱要判斷去哪裡抓藥。可能使用Switch進行判斷,這樣增加了藥就要改變劃價人員和藥房工作者的代碼。
訪問者模式的目的是封裝一些施加於某種數據結構元素之上的操作,一旦這些操作需要修改的話,接受這個操作的數據結構可以保持不變。為不同類型的元素提供多種訪問操作方式,且可以在不修改原有系統的情況下增加新的操作方式,這就是訪問者模式的模式動機。
/// <summary> /// 抽象訪問者 /// </summary> public abstract class Visitor { protected string name { get; set; } public Visitor(string name) { this.name = name; } public abstract void visitor(MedicineA a); public abstract void visitor(MedicineB b); } // 何問起 hovertree.com
/// <summary> /// 具體訪問者:劃價員 /// </summary> public class Charger :Visitor { public Charger(string name) : base(name) { } public override void visitor(MedicineA a) { Console.WriteLine("劃價員:"+this.name+"給藥"+a.GetName()+"價格:"+a.GetPrice()); } public override void visitor(MedicineB b) { Console.WriteLine("劃價員:" + this.name + "給藥" + b.GetName() + "價格:" + b.GetPrice()); } } // 何問起 hovertree.com
/// <summary> /// 具體訪問者:藥房工作者 /// </summary> public class WorkerOfPharmacy:Visitor { public WorkerOfPharmacy(string name) : base(name) { } public override void visitor(MedicineA a) { Console.WriteLine("藥房工作者:"+this.name+",拿藥:"+a.GetName()); } public override void visitor(MedicineB b) { Console.WriteLine("藥房工作者:" + this.name + ",拿藥:" + b.GetName()); } } // 何問起 hovertree.com
/// <summary> /// 抽象元素:藥 /// </summary> public abstract class Medicine { protected string name { get; set; } protected double price { get; set; } public Medicine(string name, double price) { this.name = name; this.price = price; } public string GetName() { return name; } public double GetPrice() { return price; } public void SetPrice(double price) { this.price = price; } public abstract void accept(Visitor visitor); } // 何問起 hovertree.com
/// <summary> /// 具體元素:A名稱藥 /// </summary> public class MedicineA:Medicine { public MedicineA(string name, double price) : base(name, price) { } public override void accept(Visitor visitor) { visitor.visitor(this); } } // 何問起 hovertree.com
/// <summary> /// 具體元素:B名稱藥 /// </summary> public class MedicineB:Medicine { public MedicineB(string name, double price) : base(name, price) { } public override void accept(Visitor visitor) { visitor.visitor(this); } } // 何問起 hovertree.com
/// <summary> /// 具體元素:藥單 /// </summary> public class Presciption { private List<Medicine> listmedicine = new List<Medicine>(); public void accpet(Visitor visitor) { foreach (var item in listmedicine) { item.accept(visitor); } } public void add(Medicine med) { listmedicine.Add(med); } public void remove(Medicine med) { listmedicine.Remove(med); } } // 何問起 hovertree.com
/// <summary> /// C#設計模式-訪問者模式 /// </summary> class Program { static void Main(string[] args) { //藥類型 Medicine a = new MedicineA("藥A", 10); MedicineB b = new MedicineB("藥B", 20); //藥單 Presciption presciption = new Presciption(); presciption.add(a); presciption.add(b); Visitor charger = new Charger("張三"); //劃價員 Visitor workerOfPharmacy = new WorkerOfPharmacy("李四"); //抓藥員 presciption.accpet(charger); //劃價 Console.WriteLine(); presciption.accpet(workerOfPharmacy); //抓藥 } } // 何問起 hovertree.com
優點:
1、使得新增新的訪問操作變得更加簡單。
2、能夠使得用戶在不修改現有類的層次結構下,定義該類層次結構的操作。
3、將有關元素對象的訪問行為集中到一個訪問者對象中,而不是分散搞一個個的元素類中。
缺點:
1、增加新的元素類很困難。在訪問者模式中,每增加一個新的元素類都意味著要在抽象訪問者角色中增加一個新的抽象操作,並在每一個具體訪問者類中增加相應的具體操作,違背了“開閉原則”的要求。
2、破壞封裝。當采用訪問者模式的時候,就會打破組合類的封裝。
3、比較難理解
1、對象結構中對象對應的類很少改變,但經常需要在此對象結構上定義新的操作。
2、需要對一個對象結構中的對象進行很多不同的並且不相關的操作,而需要避免讓這些操作“污染”這些對象的類,也不希望在增加新操作時修改這些類。
http://www.cnblogs.com/roucheng/p/3521864.html