两种语言实现设计模式(C++和Java)(十九:访问者模式)
在现实生活中,有些集合对象中存在多种不同的元素,且每种元素也存在多种不同的访问者和处理方式。例如,公园中存在多个景点,也存在多个游客,不同的游客对同一个景点的评价可能不同;医院医生开的处方单中包含多种药元素,査看它的划价员和药房工作人员对它的处理方式也不同,划价员根据处方单上面的药品名和数量进行划价,药房工作人员根据处方单的内容进行抓药。
UML:
Visitor Pattern 优缺点:
访问者(Visitor)模式是一种对象行为型模式,其主要优点如下。
- 扩展性好。能够在不修改对象结构中的元素的情况下,为对象结构中的元素添加新的功能。
- 复用性好。可以通过访问者来定义整个对象结构通用的功能,从而提高系统的复用程度。
- 灵活性好。访问者模式将数据结构与作用于结构上的操作解耦,使得操作集合可相对自由地演化而不影响系统的数据结构。
- 符合单一职责原则。访问者模式把相关的行为封装在一起,构成一个访问者,使每一个访问者的功能都比较单一。
访问者(Visitor)模式的主要缺点如下。
- 增加新的元素类很困难。在访问者模式中,每增加一个新的元素类,都要在每一个具体访问者类中增加相应的具体操作,这违背了“开闭原则”。
- 破坏封装。访问者模式中具体元素对访问者公布细节,这破坏了对象的封装性。
- 违反了依赖倒置原则。访问者模式依赖了具体类,而没有依赖抽象类。
举例:在药房拿药
C++ Code:
1 #include <iostream> 2 #include <string> 3 #include <list> 4 using namespace std; 5 6 class Element; 7 8 class Visitor 9 { 10 public: 11 virtual void Visit( Element *element ){}; 12 }; 13 14 // "Element" 15 class Element 16 { 17 public: 18 // Methods 19 virtual void Accept( Visitor *visitor ){}; 20 }; 21 22 23 // "ConcreteElement" 24 class Employee : public Element 25 { 26 public: 27 string name; 28 double income; 29 int vacationDays; 30 31 public : 32 Employee( string name, double income, 33 int vacationDays ) 34 { 35 this->name = name; 36 this->income = income; 37 this->vacationDays = vacationDays; 38 } 39 40 void Accept( Visitor *visitor ) 41 { 42 visitor->Visit( this ); 43 } 44 }; 45 46 class IncomeVisitor : public Visitor 47 { 48 public: 49 void Visit( Element *element ) 50 { 51 Employee *employee = ((Employee*)element); 52 employee->income *= 1.10; 53 cout<<employee->name<<" 's new income: " <<employee->income<<endl; 54 55 } 56 }; 57 58 class VacationVisitor : public Visitor 59 { 60 public : 61 void Visit( Element *element ) 62 { 63 Employee *employee = ((Employee*)element); 64 // Provide 3 extra vacation days 65 employee->vacationDays += 3; 66 cout<<employee->name<<" 's new vacation days: " <<employee->income<<endl; 67 } 68 }; 69 70 // "ObjectStructure" 71 class Employees 72 { 73 private : 74 list< Employee*> employees; 75 76 public : 77 78 void Attach( Employee *employee ) 79 { 80 employees.push_back(employee); 81 } 82 83 void Detach( Employee *employee ) 84 { 85 employees.remove(employee); 86 } 87 88 void Accept( Visitor *visitor ) 89 { 90 for (std::list<Employee*>::iterator it=employees.begin(); it != employees.end(); ++it) 91 (*it)->Accept(visitor); 92 } 93 }; 94 95 void main( ) 96 { 97 Employees *e = new Employees(); 98 e->Attach( new Employee( "Tom", 25000.0, 14 ) ); 99 e->Attach( new Employee( "Thomas", 35000.0, 16 ) ); 100 e->Attach( new Employee( "Roy", 45000.0, 21 ) ); 101 102 // Create two visitors 103 IncomeVisitor *v1 = new IncomeVisitor(); 104 VacationVisitor *v2 = new VacationVisitor(); 105 106 // Employees are visited 107 e->Accept( v1 ); 108 e->Accept( v2 ); 109 }