首页 > 代码库 > C++设计模式实现--访问者(Visitor)模式

C++设计模式实现--访问者(Visitor)模式

一. 访问者模式

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

结构如下:


二. 举例

假设有一项科学实验,是用来对比两种种子在不同环境下的生长情况。

两种种子,一种是普通的种子(Seed_A),一种是太空运回的种子(Seed_B)。

生长环境,分别是在多雨环境下(Rain_Status),阳光环境下(Sun_Status)等等。

结构如下:


代码如下:

[cpp] view plaincopy
  1. //状态  
  2. class Status  
  3. {  
  4. public:  
  5.     virtual ~Status() {}  
  6.       
  7.     virtual void VisitSeed_A(Seed* elm) {}  
  8.   
  9.     virtual void VisitSeed_B(Seed* elm) {}  
  10.   
  11. protected:  
  12.     Status() {}  
  13. };   
  14.   
  15. //下雨状态  
  16. class Rain_Status:public Status  
  17. {  
  18. public:  
  19.     Rain_Status() {}  
  20.       
  21.     virtual ~Rain_Status() {}  
  22.       
  23.     //下雨状态下A种子生长的情况  
  24.     virtual void VisitSeed_A(Seed* elm)  
  25.     {  
  26.         cout<<"Rain will visit Seed A..."<<endl;  
  27.     }  
  28.       
  29.     //下雨状态下B种子生长的情况  
  30.     virtual void VisitSeed_B(Seed* elm)  
  31.     {  
  32.         cout<<"Rain will visit Seed B..."<<endl;  
  33.     }  
  34. };   
  35.   
  36. //阳光状态  
  37. class Sun_Status:public Status  
  38. {  
  39. public:  
  40.     Sun_Status() {}  
  41.       
  42.     virtual ~Sun_Status() {}  
  43.       
  44.     //阳光状态下A种子生长的情况  
  45.     virtual void VisitSeed_A(Seed* elm)  
  46.     {  
  47.         cout<<"Sun will visit Seed A..."<<endl;  
  48.     }  
  49.       
  50.     //阳光状态下B种子生长的情况  
  51.     virtual void VisitSeed_B(Seed* elm)  
  52.     {  
  53.         cout<<"Sun will visit Seed B..."<<endl;  
  54.     }  
  55. };  
  56.   
  57.   
  58.   
  59. //种子  
  60. class Seed  
  61. {  
  62. public:  
  63.     virtual ~Seed() {}  
  64.     virtual void Accept(Status* vis) = 0;  
  65.   
  66. protected:  
  67.     Seed() {}  
  68. };  
  69.   
  70. //种子A,假设为普通种子  
  71. class Seed_A:public Seed  
  72. {  
  73. public:  
  74.     Seed_A() {}  
  75.       
  76.     ~Seed_A() {}  
  77.       
  78.     void Accept(Status* vis)  
  79.     {  
  80.         vis->VisitSeed_A(this);  
  81.     }  
  82. };   
  83.   
  84. //种子B,假设为从太空带回来的种子  
  85. class Seed_B:public Seed  
  86. {  
  87. public:  
  88.     Seed_B() {}  
  89.     ~Seed_B() {}  
  90.       
  91.     void Accept(Status* vis)  
  92.     {  
  93.         vis->VisitSeed_B(this);  
  94.     }  
  95. };  
  96.   
  97.   
  98. //对象结构类,为了对比不同种子  
  99. class ObjectStructure  
  100. {  
  101. private:  
  102.     list<Seed*> lseed;  
  103.   
  104. public:  
  105.     //Add  
  106.     void Attach(Seed* seed)  
  107.     {  
  108.         lseed.push_back(seed);  
  109.     }  
  110.   
  111.     //Delete  
  112.     void Detach(Seed* seed)  
  113.     {  
  114.         lseed.remove(seed);  
  115.     }  
  116.   
  117.     //Show  
  118.     void Display(Status* status)  
  119.     {  
  120.         list<Seed*>::iterator it = lseed.begin();  
  121.           
  122.         for (it; it != lseed.end(); ++it)  
  123.         {  
  124.             (*it)->Accept(status);  
  125.         }  
  126.     }  
  127. };  
  128.   
  129.   
  130. //测试代码  
  131. int main(int argc,char* argv[])  
  132. {  
  133.     ObjectStructure obj;  
  134.       
  135.     //加入要对比的两个种子  
  136.     obj.Attach(new Seed_A());  
  137.     obj.Attach(new Seed_B());  
  138.   
  139.     //查看各种状态下两个种子的情况  
  140.     obj.Display(new Rain_Status());  
  141.       
  142.     //Sun Satte  
  143.     obj.Display(new Sun_Status());  
  144.   
  145.     return 0;  
  146. }  

三. 说明

1. 首先有一点要明确,就是两种种子不会轻易改变,也就是只有普通和太空种子两种。换句话说就是,数据结构比较稳定

2. 可以变的是新增的状态,比如增加一个X光下的生成情况,等等。说白了就是,操作集合可以相对自由的演化

3. 这种结构的优点是,增加新的操作很容易;缺点是,增加新的数据结构有点困难,因为你要在每一个访问者里都添加相应的操作

4. 种子生长图相对于访问者模式的结构图有如下关系:

seed(种子)相当于 element(元素),这个是不怎么变的。

status(状态) 相当于 visitor(访问者),这个是可变且易变的。要注意的是,每个访问者都要对所有的元素(element)进行操作。

5. 事实上我们很少用这种模式,因为数据结构(element)不变的情况很少。