zoukankan      html  css  js  c++  java
  • 访问者模式(Visitor Pattern)

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

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

        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"类层次结构稳定,而其中的操作却经常面临频繁改动".
  • 相关阅读:
    Tomcat
    DOM/SAX/PULL解析XML
    Android网络编程 知识框架
    Chapter 10 Networking/JSON Services
    Chapter 10 Networking/Web Service Using HTTP
    Android-Universal-Image-Loader
    8.Media and Camera/Media Camera
    PAT乙级1007.素数对猜想(20)
    筛法求素数详解
    PAT乙级1006.换个格式输出整数(15)
  • 原文地址:https://www.cnblogs.com/abcdwxc/p/909482.html
Copyright © 2011-2022 走看看