zoukankan      html  css  js  c++  java
  • 访问者模式(c++实现)

    访问者模式

    模式定义

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

    模式动机

    • 访问者模式适用于数据结构相对稳定的系统
    • 它把数据结构和作用于数据结构之上的操作之间的耦合解脱开,使得操作集合可以相对自由的演化。
    • 访问者模式的目的是要把处理从数据结构分离出来。如果这样的系统有比较稳定的数据结构,又有已与变化的算法的话,使用访问者模式就是比较合适的,因为访问者模式使得算法操作的增加变得更容易。反之亦然。

    UML类图

    观察者模式

    分析:该模式相对来说比较复杂,要详细拆解一下定义和类图才能拨云见日。

    首先我们再看一下定义:访问者模式表示一个作用于某对象结构(ObjectStruct)中的各个元素(Person)操作(Action)。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作

    此具体实现中Action及其子类代表可变的行为,Person及其子类代表稳定不变的数据结构

    一句话的定义其实已经把该模式对应的UML类图给我们勾勒出来了。定义的第一句话用那么长的修饰语最后就定义了两个黑体字操作,所以说访问者模式就是操作作为访问者的模式。接下来我们对应代码好好分析一下我们理出来关键信息,我们找出了如下关键字并逐一分析:

    1. 对象结构
    2. 元素
    3. 操作

    对象结构:

    用来保存各个元素,可以把它理解为一个数据结构的管理类

    元素:

    元素就是我们定义的一个个的Action实例,它用来访问对象结构里面的元素。这里面有一个双分派的技术,就是数据结构Person对象的accept方法接收到一个方法Action对象,然后Action的对应的方法(PerformanceMan,PerformanceWoman)再把this指针传送进去,这样就完成了Action在ObjectStruct中的对对象容器的遍历访问,其实Person对象也相当于把Action注册到了自己的类内。

    操作:

    Action对象,是可变的。需要增加新的操作的时候只需要创建一个新的继承Action的类即可。然后通过ObjectStruct::Display(Action);执行。

    1. ObjectStruct::Attach(Person);
    2. ObjectStruct::Display(Action);
    3. ObjectStruct::Display(Action) { for(auto Person : LIst) Person.Accept(Action)};
    4. Person::Accept(Action){ Acction::getConcretePerson(Person)}
    5. Acction::getConcretePerson(Person){std::cout << Person.Type() << this.Type() << "什么人做什么行为";}

    这5个步骤很清晰的写出了整个模式的关键步骤。

    操作基类

    class Action
    {
    public:
        Action();
        ~Action();
        virtual void PerformanceMan(Man* man){};
        virtual void PerformanceWoman(Woman* woman){};
    };
    

    再来贴一个具体的实现类:

    #include "success.h"
    #include <iostream>
    
    Success::Success()
        :m_Type("成功")
    {
    
    }
    
    void Success::PerformanceMan(Man* man)
    {
        std::cout << man->Type() << this->m_Type << "时候的表现" << std::endl;
    
    }
    
    void Success::PerformanceWoman(Woman* woman)
    {
        std::cout << woman->Type() << this->m_Type << "时候的表现" << std::endl;
    }
    

    我们可以看到两个虚函数PerformanceManPerformanceWoman就是用来访问具体的Person(数据结构)对象的,所以说该模式适合在数据结构固定的场景使用,不然每增加一个Person子类我们都要增加Action的虚方法,用来访问新增加的Person子类,显然不符合开放封闭原则,而且Action的每一个子类都要增加相应的实现。

    源码实现

    • ObjectStruct.h
    #include "person.h"
    #include "action.h"
    #include <vector>
    #include <list>
    
    class ObjectStruct
    {
    public:
        ObjectStruct();
    
        void Display(Action* action);
    
        void Attach(Person* person);
        void Detach(Person* person);
        std::list<Person* >       m_Person;
    };
    
    • ObjectStruct.cpp
    #include "objectstruct.h"
    
    ObjectStruct::ObjectStruct()
    {
    
    }
    
    void ObjectStruct::Display(Action* action)
    {
        for(auto person : m_Person)
        {
            person->Accept(action);
        }
    }
    
    void ObjectStruct::Attach(Person *person)
    {
        m_Person.push_back(person);
    }
    
    void ObjectStruct::Detach(Person *person)
    {
        m_Person.remove(person);
    }
    
    • Action.h

      #include "man.h"
      #include "woman.h"
      
      class Action
      {
      public:
          Action();
          ~Action();
          virtual void PerformanceMan(Man* man){};
          virtual void PerformanceWoman(Woman* woman){};
      };
      
    • person.h

    class Action;
    class Person
    {
    public:
        Person();
        virtual void Accept(Action* action);
    };
    
    • success.h
    #include "action.h"
    
    class Success : public Action
    {
    public:
        Success();
    
        void PerformanceMan(Man* woman) override;
        void PerformanceWoman(Woman* woman) override;
    
    private:
        std::string     m_Type;
    };
    
    • success.cpp
    #include "success.h"
    #include <iostream>
    
    Success::Success()
        :m_Type("成功")
    {
    
    }
    
    void Success::PerformanceMan(Man* man)
    {
        std::cout << man->Type() << this->m_Type << "时候的表现" << std::endl;
    
    }
    
    void Success::PerformanceWoman(Woman* woman)
    {
        std::cout << woman->Type() << this->m_Type << "时候的表现" << std::endl;
    }
    
    • man.h
    #include "person.h"
    #include <string>
    class Man : public Person
    {
    public:
        Man();
        void Accept(Action* action) override;
        std::string Type();
    private:
        std::string m_Type;
    };
    
    
    • man.cpp
    #include "man.h"
    #include "action.h"
    
    Man::Man()
    : m_Type("男人")
    {
    
    }
    
    void Man::Accept(Action *action)
    {
        action->PerformanceMan(this);
    }
    
    std::string Man::Type()
    {
        return m_Type;
    }
    
    • main.cpp
    #include <iostream>
    #include "objectstruct.h"
    #include "man.h"
    #include "woman.h"
    #include "success.h"
    #include "failed.h"
    #include "married.h"
    #include "breakup.h"
    
    using namespace std;
    
    int main()
    {
        ObjectStruct obj;
    
        Man* man = new Man();
        obj.Attach(man);
    
        Woman*woman = new Woman();
        obj.Attach(woman);
    
        Success* success = new Success();
        obj.Display(success);
    
        Failed* failed = new Failed();
        obj.Display(failed);
    
        Married* married = new Married();
        obj.Display(married);
    
        BreakUp* breakUp = new BreakUp();
        obj.Display(breakUp);
    
        return 0;
    }
    
    
    • 其他相似的子类的详细代码就不列出了

    • 运行结果

    男人成功时候的表现

    女人成功时候的表现

    男人失败时候的表现

    女人失败时候的表现

    男人婚后时候的表现

    女人婚后时候的表现

    男人分手时候的表现

    女人分手时候的表现

    优点

    访问者模式的优点

    • 访问者模式的有点就是增加新的操作很容易,因为增加新的操作就意味着增加一个新的访问者。访问者模式将有关的行为集中到一个访问者对象中。

    缺点

    模式的缺点

    • 使增加新的数据结构变得困难。
  • 相关阅读:
    Python进阶03 模块
    Python进阶02 文本文件的输入输出
    Python进阶01 词典
    Python基础10 反过头来看看
    Python基础09 面向对象的进一步拓展
    Python基础08 面向对象的基本概念
    Python基础07 函数
    Vuex源码分析(转)
    Vue2.x双向数据绑定
    Angular2的双向数据绑定
  • 原文地址:https://www.cnblogs.com/wzxNote/p/13278443.html
Copyright © 2011-2022 走看看