• 访问者模式


    【1】什么是访问者模式?

    今天学习访问者模式,访问者模式是A对象访问B对象的一种模式。非也。

    那么,何谓访问者模式呢?真难理解!因为这个名字就TMD超晦涩,让人听不懂,或许只是此名称本身有且仅有的一个抽象意义而已。

    何谓抽象意义呢?如果你理解了《类的概念》大概你才会有所参透。

    我一直理解:抽象是多态的爸爸。怎么解释呢?你想想:

    类都是超级抽象的,而经由父类(即基类)衍生的子类(即派生类)就是 “多态” 的全部内在意义。

    访问者模式,其实没那么复杂(呵呵!或许窃理解有误)。模式即一种做法,所以一句话概述:

    把数据信息和操作行为各自分开处理而不放在一坨的做法。(要不,谁访问谁呀?你先琢磨琢磨。)

    【2】访问者模式代码示例:

    代码示例1(一般写法):

     1 #include <iostream>
     2 #include <list>
     3 #include <string>
     4 using namespace std;
     5 
     6 class Person
     7 {
     8 public:
     9     string action;
    10     virtual void getConclusion() = 0;
    11 };
    12 
    13 class Man : public Person
    14 {
    15 public:
    16     void getConclusion()
    17     {
    18         if (action == "成功")
    19         {
    20             cout << "男人成功时,背后多半有一个伟大的女人。" << endl;
    21         }
    22         else if (action == "恋爱")
    23         {
    24             cout << "男人恋爱时,凡事不懂装懂。" << endl;
    25         }
    26     }
    27 };
    28 
    29 class Woman : public Person
    30 {
    31 public:
    32     void getConclusion()
    33     {
    34         if (action == "成功")
    35         {
    36             cout << "女人成功时,背后多半有失败的男人。" << endl;
    37         }
    38         else if (action == "恋爱")
    39         {
    40             cout << "女人恋爱时,遇到事懂也装不懂。" << endl;
    41         }
    42     }
    43 };
    44 
    45 void main()
    46 {
    47     list<Person*> persons;
    48 
    49     Person *pMan1 = new Man();
    50     pMan1->action = "成功";
    51     persons.push_back(pMan1);
    52 
    53     Person *pWoman1 = new Woman();
    54     pWoman1->action = "成功";
    55     persons.push_back(pWoman1);
    56 
    57     Person *pMan2 = new Man();
    58     pMan2->action = "恋爱";
    59     persons.push_back(pMan2);
    60 
    61     Person *pWoman2 = new Woman();
    62     pWoman2->action = "恋爱";
    63     persons.push_back(pWoman2);
    64 
    65     list<Person*>::iterator iter = persons.begin();
    66     while (iter != persons.end())
    67     {
    68         (*iter++)->getConclusion();
    69     }
    70 }
    71 //Result:
    72 /*
    73 男人成功时,背后多半有一个伟大的女人。
    74 女人成功时,背后多半有失败的男人。
    75 男人恋爱时,凡事不懂装懂。
    76 女人恋爱时,遇到事懂也装不懂。
    77 */

    代码示例2(访问者模式写法):

      1 #include <iostream>
      2 #include <list>
      3 #include <string>
      4 using namespace std;
      5  
      6 class Man;
      7 class Woman;
      8 
      9 class Action
     10 {
     11 public:
     12     virtual void getManConclusion(Man *) = 0;
     13     virtual void getWomanConclusion(Woman *) = 0;
     14 }; 
     15 
     16 class Success : public Action
     17 {
     18     void getManConclusion(Man *)
     19     {
     20         cout << "男人成功时,背后多半有一个伟大的女人" << endl;
     21     }
     22     void getWomanConclusion(Woman *)
     23     {
     24         cout << "女人成功时,背后多半有不成功的男人" << endl;
     25     }
     26 
     27 };
     28 
     29 class Love : public Action
     30 {
     31     void getManConclusion(Man *)
     32     {
     33         cout << "男人恋爱时,凡事不懂装懂" << endl;
     34     }
     35     void getWomanConclusion(Woman *)
     36     {
     37         cout << "女人恋爱时,凡事懂也装不懂" << endl;
     38     }
     39 };
     40 
     41 class Person
     42 {
     43 public:
     44     virtual void accept(Action*) = 0;
     45 };
     46 
     47 class Man : public Person
     48 {
     49 public:
     50     void accept(Action* visitor)
     51     {
     52         visitor->getManConclusion(this);
     53     }
     54 };
     55 
     56 class Woman : public Person
     57 {
     58 public:
     59     void accept(Action* visitor)
     60     {
     61         visitor->getWomanConclusion(this);
     62     }
     63 };
     64 
     65 class ObjectStructure
     66 {
     67 private:
     68     list<Person*> elements;
     69 
     70 public:
     71     void attach(Person* element)
     72     {
     73         elements.push_back(element);
     74     }
     75     void detach(Person* element)
     76     {
     77         for (list<Person*>::iterator iter = elements.begin(); iter != elements.end(); ++iter)
     78         {
     79             if ((*iter) == element)
     80             {
     81                 elements.erase(iter);
     82             }
     83         }
     84     }
     85     void display(Action *visitor)
     86     {
     87         for (list<Person*>::iterator iter = elements.begin(); iter != elements.end(); ++iter)
     88         {
     89             (*iter)->accept(visitor);
     90         }
     91     }
     92 };
     93 
     94 int main()
     95 {
     96     ObjectStructure objStructure;
     97     Success *os = new Success();
     98     Love *lv = new Love();
     99 
    100     Person *man = new Man();
    101     objStructure.attach(man);
    102      
    103     Person *woman = new Woman();
    104     objStructure.attach(woman);
    105 
    106     objStructure.display(os);
    107     objStructure.display(lv);
    108 
    109     return 0;
    110 }
    111 //Result:
    112 /*
    113 男人成功时,背后多半有一个伟大的女人
    114 女人成功时,背后多半有不成功的男人
    115 男人恋爱时,凡事不懂装懂
    116 女人恋爱时,凡事懂也装不懂
    117 */
    View Code

     【3】访问者模式角色分析

    在访问者模式中,主要包括下面几个角色:

    抽象访问者:一般为抽象类或者接口(如上例Action),声明访问者可以访问哪类元素。

          具体到程序中就是visit方法中的参数定义哪些类型的元素是可以被访问的。

    访问者:实现抽象访问者所声明的方法(如上例Success,Love),它影响到访问者具体访问到一种元素后该干什么,要做什么事情。

    抽象元素类(被访问者):一般为抽象类或者接口(如上例Person),声明接受哪一类访问者访问,程序上是通过accept方法中的参数来定义的。

          抽象元素一般有两类方法,一部分是本身的业务逻辑,另外就是允许接收哪类访问者来访问。

    元素类(被访问者):实现抽象元素类所声明的accept方法(如上例Man,Woman),通常都是以this指针为实参,基本上已经形成一种定式。

    元素对象(被访问者)容器:一个元素的容器(如上例ObjectStructure),一般包含一个容纳多个不同类、不同接口的容器,如List、Set、Map等,在项目中一般很少抽象出这个角色。

    【4】访问者模式总结

    应用情景:访问者模式适用于数据结构稳定的系统。实质上把数据结构和作用于数据结构上的操作分离开。

    因为访问者模式使得算法操作增加变得更容易。若系统数据结构对象易于变化,经常有新的数据对象增加进来,则不适合使用访问者模式。

    优点:新增加操作很容易,因为新增加操作相当于增加一个访问者。

    由以上示例可以得知:访问者模式将有限的行为操作(访问者)集中到有限个数据结构(访问者)对象上。

    比如,我们现在需求再增加一个“失败”的操作。只需要继承自Action再实现一个所谓的 “失败” 访问者即可。

     

    Good  Good   Study,  Day  Day   Up.

    顺序  选择   循环  总结

  • 相关阅读:
    PLSQL查询显示乱码或者问号
    Sonar 扫描C#代码 排除文件
    C# 短日期转换为DateTime
    电脑远程连接不上或者ip的地址一直是169.254
    C#导出CSV或者EXCEL文件转换文本
    Oracle 计算两个日期相差天时分秒
    Linux 做网关
    Python 内置函数
    Python Fileinput 模块
    Python-2.7 配置 tab 自动补全功能
  • 原文地址:https://www.cnblogs.com/Braveliu/p/3957007.html
Copyright © 2020-2023  润新知