设计模式——访问者

来源:互联网 发布:java实现手写数字识别 编辑:程序博客网 时间:2024/06/15 19:34

我们去银行柜台办业务,一般情况下会开几个个人业务柜台的,你去其中任何一个柜台办理都是可以的。我们的访问者模式可以很好付诸在这个场景中:对于银行柜台来说,他们是不用变化的,就是说今天和明天提供个人业务的柜台是不需要有变化的。而我们作为访问者,今天来银行可能是取消费流水,明天来银行可能是去办理手机银行业务,这些是我们访问者的操作,一直是在变化的。

访问者模式就是表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。 

类图和样例:


抽象访问者(Visitor)角色:声明了一个或者多个访问操作,形成所有的具体元素角色必须实现的接口。

具体访问者(ConcreteVisitor)角色:实现抽象访问者角色所声明的接口,也就是抽象访问者所声明的各个访问操作。

抽象节点(Element)角色:声明一个接受操作,接受一个访问者对象作为一个参量。

具体节点(ConcreteElement)角色:实现了抽象元素所规定的接受操作。

结构对象(ObiectStructure)角色:有如下的一些责任,可以遍历结构中的所有元素;如果需要,提供一个高层次的接口让访问者对象可以访问每一个元素;如果需要,可以设计成一个复合对象或者一个聚集,如列(List)或集合(Set)。 

样例:

[cpp] view plaincopy
  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. }  

优缺点:

访问者模式有如下的优点:

1访问者模式使得增加新的操作变得很容易。如果一些操作依赖于一个复杂的结构对象的话,那么一般而言,增加新的操作会很复杂。而使用访问者模式,增加新的操作就意味着增加一个新的访问者类,因此,变得很容易。

2访问者模式将有关的行为集中到一个访问者对象中,而不是分散到一个个的节点类中。

3访问者模式可以跨过几个类的等级结构访问属于不同的等级结构的成员类。迭代子只能访问属于同一个类型等级结构的成员对象,而不能访问属于不同等级结构的对象。访问者模式可以做到这一点。

4积累状态。每一个单独的访问者对象都集中了相关的行为,从而也就可以在访问的过程中将执行操作的状态积累在自己内部,而不是分散到很多的节点对象中。这是有益于系统维护的优点。

访问者模式有如下的缺点:

1增加新的节点类变得很困难。每增加一个新的节点都意味着要在抽象访问者角色中增加一个新的抽象操作,并在每一个具体访问者类中增加相应的具体操作。

2破坏封装。访问者模式要求访问者对象访问并调用每一个节点对象的操作,这隐含了一个对所有节点对象的要求:它们必须暴露一些自己的操作和内部状态。不然,访问者的访问就变得没有意义。由于访问者对象自己会积累访问操作所需的状态,从而使这些状态不再存储在节点对象中,这也是破坏封装的。

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 受风引起的面瘫怎么办 两边的脸不一样大怎么办 脖子扭到怎么办快速好 卡马西平片过量怎么办 天冷眼睛神经跳怎么办 每天失眠怎么办要疯了 老是失眠是怎么办才好 汗毛又多又长怎么办 脸上出油毛孔粗大黑头怎么办 毛长在皮肤里怎么办 腰韧带拉伤怎么办恢复快 脚扭伤伤了韧带怎么办 膝关节韧带拉伤怎么办恢复快 脚踝韧带拉伤怎么办恢复快 脚扭伤一年没好怎么办 脚扭伤半年还疼怎么办 脚崴过有后遗症怎么办 脚扭伤脚面肿了怎么办 腰突然扭了好痛怎么办 腰扭伤了怎么办最有效 腰扭伤了不能动怎么办 前交叉韧带增粗怎么办 膝盖前交叉韧带损伤怎么办 狗的腿肌肉拉伤怎么办 胳膊上的筋拉伤怎么办 肩周炎胳膊抬不起来怎么办 脖子上的筋拉伤怎么办 脚踝骨扭伤肿了怎么办 脚扭伤肿起来了怎么办 月经量特别少该怎么办 月经血沾床单上怎么办 月经弄到棉被上怎么办 血弄床单上干了怎么办 不小心吃了指甲怎么办 月经没有干净同房了怎么办 撞红了怎么办要吃药吗 自己长得太丑怎么办 长得丑特别自卑怎么办 手挤了有淤血怎么办 手指肚夹淤血了怎么办 指甲被夹了变黑怎么办