因为应用开发过程当中先前完成的类型会由于需求变化(不管是业务功能,仍是技术实现或是出于集成的须要)增长新的方法,若是直接在基类中增长新的方法,其派生类型可能须要相应进行比较繁琐的处理。而使用访问者模式能够作到在不改变既有类型层次的前提下,运行时动态为类型层次的每一个类增长新的操做。设计模式
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