zoukankan      html  css  js  c++  java
  • 【设计模式】——访问者模式

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

    访问者模式结构图

      访问者模式使用与数据结构相对比较稳定的系统,即数据结构和作用与结构上的操作之间的耦合解脱开,使得操作集合可以相对自由的演化。其目的,要把处理从数据结构分离开来。很多系统可以按照算法和数据结构分开,如果这样的系统有比较稳定的数据结构,又有易于变化的算法的话,使用访问者模式就是比较合适的,因为访问者模式使得算法操作的增加变得容易。反之,如果这样的系统的数据结构对象易于变化,经常要有新的数据结构对象增加进来,就不适合使用访问者模式。

      访问者模式的优点就是增加新的操作很容易,因为增加新的操作就意味着增加一个新的访问者。访问者模式将有关的行为集中到一个访问者对象中。缺点是使增加新的数据结构变得困难了。

      其实,大多时候你并不需要访问者模式,但当一旦需要访问者模式时,那就是真的需要它了。

    #include <iostream>
    #include <list>
    using namespace std;
    class ConcreteElementA;
    class ConcreteElementB;
    //Visitor类,为该对象结构中ConcreteElement的每一个类声明一个Visit操作
    class Visitor
    {
    public:
        virtual void VisitConcreteElementA(ConcreteElementA *concreteElementA)=0;
        virtual void VisitConcreteElementB(ConcreteElementB *concreteElementB)=0;
    };
    //ConcreteVisitor1和ConcreteVisitor2类,具体访问者,实现每个由Visitor声明的操作。每个操作实现算法的一部分,
    //而该算法片段乃是对应于结构中对象的类。
    class ConcreteVisitor1:public Visitor
    {
    public:
        void VisitConcreteElementA(ConcreteElementA *concreteElementA)
        {
            cout << "ConcreteElementA被ConcreteVisitor1访问" << endl;
        }
        void VisitConcreteElementB(ConcreteElementB *concreteElementB)
        {
            cout << "ConcreteElementB被ConcreteVisitor1访问" << endl;
        }
    };
    class ConcreteVisitor2:public Visitor
    {
    public:
        void VisitConcreteElementA(ConcreteElementA *concreteElementA)
        {
            cout << "ConcreteElementA被ConcreteVisitor2访问" << endl;
        }
        void VisitConcreteElementB(ConcreteElementB *concreteElementB)
        {
            cout << "ConcreteElementB被ConcreteVisitor2访问" << endl;
        }
    };
    //Element类,定义一个Accept操作,它以一个访问者为参数
    class Element
    {
    public:
        virtual void Accept(Visitor *visitor)=0;
    };
    //ConcreteElementA和ConcreteElementB类,具体元素,实现Accept操作
    class ConcreteElementA:public Element
    {
    public:
        //充分利用双分派技术,实现处理与数据结构的分离
        void Accept(Visitor *visitor)
        {
            visitor->VisitConcreteElementA(this);
        }
        void OperationA()
        {
            cout << "具体元素A的其他相关方法" << endl;
        }
    };
    class ConcreteElementB:public Element
    {
    public:
        //充分利用双分派技术,实现处理与数据结构的分离
        void Accept(Visitor *visitor)
        {
            visitor->VisitConcreteElementB(this);
        }
        void OperationA()
        {
            cout << "具体元素B的其他相关方法" << endl;
        }
    };
    //ObjectStructure类,能枚举它的元素,可以提供一个高层的接口以允许访问者访问它的元素
    class ObjectStructure
    {
    private:
        list<Element*> m_list;
    public:
        void Attach(Element *element)
        {
            m_list.push_back(element);
        }
        void Detach(Element *element)
        {
            m_list.remove(element);
        }
        void Accept(Visitor *visitor)
        {
            list<Element*>::iterator iter;
            for(iter=m_list.begin();iter!=m_list.end();iter++)
            {
                if(*iter!=NULL)
                    (*iter)->Accept(visitor);
            }
        }
    };
    int main()
    {
        ObjectStructure *o=new ObjectStructure();
        o->Attach(new ConcreteElementA());
        o->Attach(new ConcreteElementB());
        ConcreteVisitor1 *v1=new ConcreteVisitor1();
        ConcreteVisitor2 *v2=new ConcreteVisitor2();
        o->Accept(v1);
        o->Accept(v2);
        return 0;
    }

      通常ConcreteVisitor可以单独开发,不必跟ConcreteElementA或ConcreteElementB写在一起。正因为这样,ConcreteVisitor能提高ConcreteElement之间的独立性,如果把一个处理动作设计成ConcreteElementA和ConcreteElementB类的方法,每次想新增“处理”以扩充功能时就得去修改ConcreteElementA和ConcreteElementB了。

    下面是关于男人和女人的访问者模式例子

    #include <iostream>
    #include <list>
    using namespace std;
    class Man;
    class Woman;
    class Action
    {
    public:
        virtual void GetManConclusion(Man *concreteElementA)=0;
        virtual void GetWomanConclusion(Woman *concreteElementB)=0;
    };
    class Person
    {
    public:
        //获取状态对象
        virtual void Accept(Action *visiton)=0;
    };
    //这里的关键在于只分为男人和女人,这个性别的分类是稳定的,所以可以在状态类镇南关,增加“男人反应”和“女人反映”两个方法,方法个数
    //是稳定的,不会很容易的发生变化。而“人”抽象类中有一个抽象方法“接受”,它是用来获得“状态”对象的。每一种具体状态都继承“状态”
    //抽象类,实现两个反应方法
    class Success:public Action
    {
    public:
        void GetManConclusion(Man *concreteElementA)
        {
            cout << "男人成功时,背后多半有一个伟大的女人。" << endl;
        }
        void GetWomanConclusion(Woman *concretementB)
        {
            cout << "女人成功时,背后大多有一个不成功的男人。" << endl;
        }
    };
    class Failing:public Action
    {
    public:
        void GetManConclusion(Man *concreteElementA)
        {
            cout << "男人失败时,闷头喝酒,谁也不用劝。" << endl;
        }
        void GetWomanConclusion(Woman *concretementB)
        {
            cout << "女人失败时,眼泪汪汪,谁也劝不了。" << endl;
        }
    };
    class Amativeness:public Action
    {
    public:
        void GetManConclusion(Man *concreteElementA)
        {
            cout << "男人恋爱时,凡是不懂也要装懂。" << endl;
        }
        void GetWomanConclusion(Woman *concretementB)
        {
            cout << "女人恋爱时,遇事懂也装作不懂。" << endl;
        }
    };
    class Man:public Person
    {
    public:
        void Accept(Action *visitor)
        {
            visitor->GetManConclusion(this);
        }
    };
    class Woman:public Person
    {
    public:
        void Accept(Action *visiton)
        {
            visiton->GetWomanConclusion(this);
        }
    };
    //对象结构
    class ObjectStructure
    {
    private:
        list<Person*> m_list;
    public:
        void Attach(Person *element)
        {
            m_list.push_back(element);
        }
        void Detach(Person *element)
        {
            m_list.remove(element);
        }
        void Display(Action *visitor)
        {
            list<Person*>::iterator iter=m_list.begin();
            for(;iter!=m_list.end();iter++)
            {
                if(NULL!=*iter)
                    (*iter)->Accept(visitor);
            }
        }
    };
    int main()
    {
        ObjectStructure *o=new ObjectStructure();
        o->Attach(new Man());
        o->Attach(new Woman());
        Success *v1=new Success();
        o->Display(v1);
        Failing *v2=new Failing();
        o->Display(v2);
        Amativeness *v3=new Amativeness();
        o->Display(v3);
        return 0;
    }
  • 相关阅读:
    C# 创建线程
    离最近发表时间代码
    ORA12154: TNS: 无法解析指定的连接标识符
    SQL和LINQ按年月、按类型显示文章篇数
    对象的序列化和反序列化
    父类与子类间的隐藏与重写
    C# 进程启动与关闭
    猫叫老鼠跑的事件例子
    第十八章 12判断string类型字符串是否为空 简单
    第十八章 11 string字符串的比较 简单
  • 原文地址:https://www.cnblogs.com/awy-blog/p/3848172.html
Copyright © 2011-2022 走看看