Don't think you are, know you are

博客园 首页 新随笔 管理




// Visitor pattern -- Real World example  

using System;
using System.Collections;

namespace DoFactory.GangOfFour.Visitor.RealWorld
{
  
  
// MainApp startup application 

  
class MainApp
  {
    
static void Main()
    {
      
// Setup employee collection 
      Employees e = new Employees();
      e.Attach(
new Clerk());
      e.Attach(
new Director());
      e.Attach(
new President());

      
// Employees are 'visited' 
      e.Accept(new IncomeVisitor());
      e.Accept(
new VacationVisitor());

      
// Wait for user 
      Console.Read();
    }
  }

  
// "Visitor" 

  
interface IVisitor
  {
    
void Visit(Element element);
  }

  
// "ConcreteVisitor1" 

  
class IncomeVisitor : IVisitor
  {
    
public void Visit(Element element)
    {
      Employee employee 
= element as Employee;

      
// Provide 10% pay raise 
      employee.Income *= 1.10;
      Console.WriteLine(
"{0} {1}'s new income: {2:C}"
        employee.GetType().Name, employee.Name, 
        employee.Income);
    }
  }

  
// "ConcreteVisitor2" 

  
class VacationVisitor : IVisitor
  {
    
public void Visit(Element element)
    {
      Employee employee 
= element as Employee;
      
      
// Provide 3 extra vacation days 
      Console.WriteLine("{0} {1}'s new vacation days: {2}"
        employee.GetType().Name, employee.Name, 
        employee.VacationDays);
    }
  }

  
class Clerk : Employee
  {
    
// Constructor 
    public Clerk() : base("Hank"25000.014)
    { 
    }
  }

  
class Director : Employee
  {
    
// Constructor 
    public Director() : base("Elly"35000.016)
    {  
    }
  }

  
class President : Employee
  {
    
// Constructor 
    public President() : base("Dick"45000.021)
    {  
    }
  }

  
// "Element" 

  
abstract class Element
  {
    
public abstract void Accept(IVisitor visitor);
  }

  
// "ConcreteElement" 

  
class Employee : Element
  {
    
string name;
    
double income;
    
int vacationDays;

    
// Constructor 
    public Employee(string name, double income, 
      
int vacationDays)
    {
      
this.name = name;
      
this.income = income;
      
this.vacationDays = vacationDays;
    }

    
// Properties 
    public string Name
    {
      
getreturn name; }
      
set{ name = value; }
    }

    
public double Income
    {
      
getreturn income; }
      
set{ income = value; }
    }

    
public int VacationDays
    {
      
getreturn vacationDays; }
      
set{ vacationDays = value; }
    }

    
public override void Accept(IVisitor visitor)
    {
      visitor.Visit(
this);
    }
  }

  
// "ObjectStructure" 

  
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(IVisitor visitor)
    {
      
foreach (Employee e in employees)
      {
        e.Accept(visitor);
      }
      Console.WriteLine();
    }
  }
}
 

Output

Clerk Hank
's new income: $27,500.00
Director Elly's new income: $38,500.00
President Dick's new income: $49,500.00

Clerk Hank
's new vacation days: 14
Director Elly's new vacation days: 16
President Dick's new vacation days: 21
 


Visitor 模式给我们提供了无需更改一个层次结构中的类即可修改其行为或者说表现的方法。

代价就是用           visitor.Visit(this);               用this将自己“出卖”。

如果说 Mediator 是对象之间的潜规则,那么 Visitor 就是对象自己对自己的潜规则。注意看客户端,只是接受不同的Visitor而产生了类自身的不同表现。

Visitor模式一个非常常见的应用是,便利大量的数据结构产生报表。数据结构对象中不含有任何产生报表的代码。如果想增加新报表,只需增加新的访问者,而不需更改数据结构中的代码。一般来说,如果一个应用程序中存在有需要以多种不同方式进行解释的数据结构,就可以使用Visitor模式。任何增加或更改访问者的行为都不会需要现有数据结构的重新编译和部署,这就是Visitor模式的威力。

包含大量数据的对象,最好提供Accept方法将自己出卖,这样可以减轻自己的负担,就像SUNZA歌里唱的,"open your mind , you can do everyhing! " 。

posted on 2007-08-06 21:37  炭炭  阅读(306)  评论(0编辑  收藏  举报