因爲應用開發過程當中先前完成的類型會由於需求變化(不管是業務功能,仍是技術實現或是出於集成的須要)增長新的方法,若是直接在基類中增長新的方法,其派生類型可能須要相應進行比較繁瑣的處理。而使用訪問者模式能夠作到在不改變既有類型層次的前提下,運行時動態爲類型層次的每一個類增長新的操做。設計模式
GOF對策略模式的描述爲:
Represent an operation to be performed on the elements of an object structure. Visitor lets you define a new operation without changing the classes of the elements on which it operates...
— Design Patterns : Elements of Reusable Object-Oriented Softwarethis
UML類圖
設計
訪問者模式包含五種角色:code
設想有這樣一個HR系統,系統只能按照標準的工做時間、時薪計算薪金,在系統交付後發現須要提供加班計算功能,並且還須要安排休假、晉升等功能,考慮到相似的需求在未來還會出現,因此改造的時候考慮採用訪問者模式。在HR系統的對象上增長了Accept某個IVisistor接口的能力,在添加新功能的時候能夠實現IVisitor接口。orm
public interface IEmployee { string Name { get; set; } double Income { get; set; } int VacationDays { get; set; } void Accept(IVisitor visitor); } public interface IVisitor { void VisitiEmployee(IEmployee employee); void VisitManager(Manager manager); } public class Employee : IEmployee { public string Name { get; set; } public double Income { get; set; } public int VacationDays { get; set; } public Employee(string name, double income, int vacationDays) { this.Name = name; this.Income = income; this.VacationDays = vacationDays; } public void Accept(IVisitor visitor) { visitor.VisitiEmployee(this); } } public class Manager : IEmployee { public string Department { get; set; } public string Name { get; set; } public double Income { get; set; } public int VacationDays { get; set; } public Manager(string name, double income, int vacationDays, string department) { this.Name = name; this.Income = income; this.VacationDays = vacationDays; this.Department = department; } public void Accept(IVisitor visitor) { visitor.VisitManager(this); } } public class EmployeeCollection : List<IEmployee> { public void Accept(IVisitor visitor) { foreach (IEmployee employee in this) { employee.Accept(visitor); } } } public class ExtraVacationVisitor : IVisitor { public void VisitiEmployee(IEmployee employee) { employee.VacationDays += 1; } public void VisitManager(Manager manager) { manager.VacationDays += 2; } } public class RaiseSalaryVisitor : IVisitor { public void VisitiEmployee(IEmployee employee) { employee.Income *= 1.1; } public void VisitManager(Manager manager) { manager.Income *= 1.2; } }
調用端代碼對象
public class Test { public static void Entry() { EmployeeCollection employees = new EmployeeCollection(); employees.Add(new Employee("joe", 25000, 14)); employees.Add(new Manager("alice", 22000, 14, "sales")); employees.Add(new Employee("peter", 15000, 7)); employees.Accept(new ExtraVacationVisitor()); employees.Accept(new RaiseSalaryVisitor()); } }
Employee類型並無加薪和修改休假天數的方法,但藉助訪問者模式,時期具備了對應的功能。訪問者模式的關鍵代碼是在數據基礎類裏面有一個方法接受訪問者,將自身引用傳入訪問者,這樣訪問者就能夠操做數據類了。blog
優勢接口
參考書籍:
王翔著 《設計模式——基於C#的工程化實現及擴展》element