Terry's blog

Focus on bigdata and cloud.

博客园 首页 新随笔 联系 订阅 管理
  383 Posts :: 1 Stories :: 256 Comments :: 51 Trackbacks
类层次结构的变化:
    类层次结构中可能经常由于引入新的操作,从而将类型变得脆弱...
                          
动机:
    在软件构建过程中,由于需求的改变,某些类层次结构中常常需要增加新的行为(方法),如果直接在基类中做这样的更改,将会给子类带来很繁重的变更负担,甚至破坏原有设计。
    如何在不更改类层次结构的前提下,在运行时根据需要透明地为类层次结构上的各个类动态添加新的操作,从而避免上述问题?

意图:
    表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这引起元素的新操作。
结构:
            
适用性:

    1.一个对象结构包含很多类对象,它们有不同的接口,而你想对这些对象实施一些依赖于其具体类的操作。
    2.需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而你想避免让这些操作"污染"这些对象的类。Visitor使得你可以将相关的操作集中起来定义在一个类中。当该对象结构被很多应用共享时,用Visitor模式让每个应用仅包含需要用到的操作。
    3.定义对象结构的类很少改变,但经常需要在结构上定义新的操作。改变对象结构类需要重定义对所有访问者的接口,这可能需要很大的代价。如果对象结构类经常改变,那么可能还是在这些类中定义这些操作较好。
代码实现:
   

  1 // MainApp startup application
  2 
  3   class MainApp
  4   {
  5     static void Main()
  6     {
  7       // Setup employee collection
  8       Employees e = new Employees();
  9       e.Attach(new Clerk());
 10       e.Attach(new Director());
 11       e.Attach(new President());
 12 
 13       // Employees are 'visited'
 14       e.Accept(new IncomeVisitor());
 15       e.Accept(new VacationVisitor());
 16 
 17       // Wait for user
 18       Console.Read();
 19     }
 20   }
 21 
 22   // "Visitor"
 23 
 24   interface IVisitor
 25   {
 26     void Visit(Element element);
 27   }
 28 
 29   // "ConcreteVisitor1"
 30 
 31   class IncomeVisitor : IVisitor
 32   {
 33     public void Visit(Element element)
 34     {
 35       Employee employee = element as Employee;
 36 
 37       // Provide 10% pay raise
 38       employee.Income *= 1.10;
 39       Console.WriteLine("{0} {1}'s new income: {2:C}",
 40         employee.GetType().Name, employee.Name,
 41         employee.Income);
 42     }
 43   }
 44 
 45   // "ConcreteVisitor2"
 46 
 47   class VacationVisitor : IVisitor
 48   {
 49     public void Visit(Element element)
 50     {
 51       Employee employee = element as Employee;
 52       
 53       // Provide 3 extra vacation days
 54       Console.WriteLine("{0} {1}'s new vacation days: {2}",
 55         employee.GetType().Name, employee.Name,
 56         employee.VacationDays);
 57     }
 58   }
 59 
 60   class Clerk : Employee
 61   {
 62     // Constructor
 63     public Clerk() : base("Hank"25000.014)
 64     {
 65     }
 66   }
 67 
 68   class Director : Employee
 69   {
 70     // Constructor
 71     public Director() : base("Elly"35000.016)
 72     {  
 73     }
 74   }
 75 
 76   class President : Employee
 77   {
 78     // Constructor
 79     public President() : base("Dick"45000.021)
 80     {  
 81     }
 82   }
 83 
 84   // "Element"
 85 
 86   abstract class Element
 87   {
 88     public abstract void Accept(IVisitor visitor);
 89   }
 90 
 91   // "ConcreteElement"
 92 
 93   class Employee : Element
 94   {
 95     string name;
 96     double income;
 97     int vacationDays;
 98 
 99     // Constructor
100     public Employee(string name, double income,
101       int vacationDays)
102     {
103       this.name = name;
104       this.income = income;
105       this.vacationDays = vacationDays;
106     }
107 
108     // Properties
109     public string Name
110     {
111       getreturn name; }
112       set{ name = value; }
113     }
114 
115     public double Income
116     {
117       getreturn income; }
118       set{ income = value; }
119     }
120 
121     public int VacationDays
122     {
123       getreturn vacationDays; }
124       set{ vacationDays = value; }
125     }
126 
127     public override void Accept(IVisitor visitor)
128     {
129       visitor.Visit(this);
130     }
131   }
132 
133   // "ObjectStructure"
134 
135   class Employees
136   {
137     private ArrayList employees = new ArrayList();
138 
139     public void Attach(Employee employee)
140     {
141       employees.Add(employee);
142     }
143 
144     public void Detach(Employee employee)
145     {
146       employees.Remove(employee);
147     }
148 
149     public void Accept(IVisitor visitor)
150     {
151       foreach (Employee e in employees)
152       {
153         e.Accept(visitor);
154       }
155       Console.WriteLine();
156     }
157   }
运行结果:
      
Visoitr模式的几个要点:

    1.Visitor模式通过所谓双重分发(double dispatch)来实现在不更改Element类层次结构的前提下,在运行时透明地为类层次结构上的各个类动态添加新的操作。
    2.所谓双重分发却Visotor模式中间包括了两个多态分发(注意其中的多态机制);第一个为accept方法的多态辨析;第二个为visitor方法的多态辨析。
    3.Visotor模式的最大缺点在于扩展类层次结构(增添新的Element子类),会导致Visitor类的改变。因此Visiotr模式适用"Element"类层次结构稳定,而其中的操作却经常面临频繁改动".
posted on 2007-09-28 16:07  王晓成  阅读(...)  评论(... 编辑 收藏