访问者模式
动机:
在软件构建过程中,由于需求的改变,某些类层次结构中常常需要增加新的行为(方法),如果直接在基类中做这样的更改,将会给子类带来很繁重的变更负担,甚至破坏原有设计。
如何在不更改类层次结构的前提下,在运行时根据需要透明地为类层次结构上的各个类动态添加新的操作,从而避免上述问题?
适用性:
1.一个对象结构包含很多类对象,它们有不同的接口,而你想对这些对象实施一些依赖于其具体类的操作。
2.需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而你想避免让这些操作"污染"这些对象的类。Visitor使得你可以将相关的操作集中起来定义在一个类中。当该对象结构被很多应用共享时,用Visitor模式让每个应用仅包含需要用到的操作。
3.定义对象结构的类很少改变,但经常需要在结构上定义新的操作。改变对象结构类需要重定义对所有访问者的接口,这可能需要很大的代价。如果对象结构类经常改变,那么可能还是在这些类中定义这些操作较好。
该模式适用于某种操作是固定的,但是会存在不同的访问者,访问者的模式都是固定的(即方法都是来源统一的接口),只不过内部实现的方式与逻辑不同,但是访问的那一方基本固定。
通过被访问者可以接受访问者,在被访问者中应该访问者访问本实例,实现逻辑实现全部在访问者访问中!
(访问者需要访问Visit对象)(被访问者需要接收Accept访问者)
//访问者接口 interface IVistor { void Vist(Element element); }
//具体访问者(这个就是不确定,可以变化的访问者) class IncomeVisitor : IVistor { public void Vist(Element element) { Employee employee = element as Employee; employee.Income *= 1.1; Console.WriteLine("{0} {1}'s new income {2:C}",this.GetType().Name, employee.Name,employee.Income); } } class VacationVisitor : IVistor { public void Vist(Element element) { Employee employee = element as Employee; Console.WriteLine("{0} {1}'s new vactionDays {2}", this.GetType().Name, employee.Name, employee.VacationDays); } }
// 抽象要素 abstract class Element { public abstract void Accept(IVistor ivistor); }
// 结构要素 class Employee : Element { string _name; double _income; int _vacationDays; public Employee(string name,double income,int vacationDays) { _name = name; _income = income; _vacationDays = vacationDays; } public string Name { get { return _name; } set { _name = value; } } public double Income { get { return _income; } set { _income = value; } } public int VacationDays { get { return _vacationDays; } set { _vacationDays = value; } } public override void Accept(IVistor ivistor) { ivistor.Vist(this); } }
//具体对象结构 class Employees { private ArrayList employees = new ArrayList(); public void Attach(Employee employee) { employees.Add(employee); } public void Detach(Employee employee) { employees.Remove(employee); } public void Accept(IVistor ivistor) { foreach (Employee employee in employees) { employee.Accept(ivistor); } } }
//调用 static void Main(string[] args) { Employees employees = new 访问者模式.Employees(); employees.Attach(new 访问者模式.Employee("xiawang",18500,3)); employees.Attach(new 访问者模式.Employee("luxi", 23000, 2)); employees.Accept(new IncomeVisitor()); employees.Accept(new VacationVisitor()); Console.ReadKey(); }
结果: