设计模式---行为变化模式之访问器模式(Visitor)

Posted ssyfj

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了设计模式---行为变化模式之访问器模式(Visitor)相关的知识,希望对你有一定的参考价值。

一:概念

访问者模式,是行为模式之一,它分离对象的数据和行为,使用Visitor模式,可以不修改已有类的情况下,增加新的操作角色和职责。

二:动机

在软件构建的过程中,由于需求的改变,某些类层次结构中常常需要增加新的行为(方法)。如果直接在类中做这样的更改,将会给子类带来很繁重的变更负担,甚至破坏原有设计
如何在不更改类层次结构的前提下,在运行时根据需要透明地为类层次结构上的各个类动态添加新的操作,从而避免上述问题?

三:代码讲解

(一)原代码

#include <iostream>
using namespace std;

class Visitor;

class Element
{
public:
    virtual void Func1() = 0;
    
    virtual ~Element(){}
};

class ElementA : public Element
{
public:
    void Func1() override{
        //...
    }
};

class ElementB : public Element
{
public:
    void Func1() override{
        //***
    }
};

需求:想要增加一个新的功能

#include <iostream>
using namespace std;

class Visitor;


class Element
{
public:
    virtual void Func1() = 0;
    
    virtual void Func2(int data)=0;  //定义虚方法,后面继承父类的都要一一实现
    virtual void Func3(int data)=0;
    //...
    
    virtual ~Element(){}
};

class ElementA : public Element
{
public:
    void Func1() override{
        //...
    }
    
    void Func2(int data) override{
        //...
    }
};

class ElementB : public Element
{
public:
    void Func1() override{
        //***
    }
    
    void Func2(int data) override {
        //***
    }
};
这不是一个好的方法,在部署后,我们再次修改,此时的代价是十分高的,违背了开闭原则

(二)visitor模式---->前提:能够预料到未来可能会为这整个类层次结构添加新的操作,但是我不知道要加多少操作,什么操作

1.预先设计Element基类

class Visitor;

class Element
{
public:
    virtual void accept(Visitor& visitor) = 0; //第一次多态辨析
  //accept方法为将来埋下伏笔,将来要添加新的功能,加到这里去找他,进行绑定visitor
    virtual ~Element(){}
};

2.完善visitor基类

class Visitor{
public:
    virtual void visitElementA(ElementA& element) = 0;  //针对每一个子类生成一个方法对应
    virtual void visitElementB(ElementB& element) = 0;
    
    virtual ~Visitor(){}
};

3.element子类实现

class ElementA : public Element
{
public:
    void accept(Visitor &visitor) override {
        visitor.visitElementA(*this);
    }
};

class ElementB : public Element
{
public:
    void accept(Visitor &visitor) override {
        visitor.visitElementB(*this); //第二次多态辨析
    }

};

=========================上面实现了:预先的设计了我将来可能会增加的新的操作=============================

4.将来,要为前面的整个类层次结构添加新的操作,添加visitor子类,在子类中扩展

//扩展1  将来
class Visitor1 : public Visitor{
public:
    void visitElementA(ElementA& element) override{
        cout << "Visitor1 is processing ElementA" << endl;
    }
        
    void visitElementB(ElementB& element) override{
        cout << "Visitor1 is processing ElementB" << endl;
    }
};
     
//扩展2  将来的将来
class Visitor2 : public Visitor{
public:
    void visitElementA(ElementA& element) override{
        cout << "Visitor2 is processing ElementA" << endl;
    }
    
    void visitElementB(ElementB& element) override{
        cout << "Visitor2 is processing ElementB" << endl;
    }
};

5.操作绑定

int main()
{
    Visitor2 visitor;
    ElementB elementB;
    elementB.accept(visitor);// double dispatch  将visitor2中的新的visitElementA操作添加到elementB中
    
    ElementA elementA;
    elementA.accept(visitor);  //将Visitor2中新的visitElementB新操作添加到了elementA中

    
    return 0;
}

四:模式定义

表示一个作用与某对像结构中的各元素的操作。使得可以在不改变(稳定)各元素的类的前提下定义(扩展)作用于这些元素的新操作(变化)。

                                                                                        ——《设计模式》GoF

五:类图(结构)

技术分享图片

visitor要预先知道(依赖于)我们具体的ELement子类,所以我们要提前设置好其子类,之后基本不会修改我们修改的只有visitor扩展子类。
所以Element子类是稳定的
(必须提前确定下来,但是常常确定不了,我们一增加element子类,visitor基类就要做出相应改变,子类也是,全部的稳定性都混乱了,打破了开闭原则,全部都要重新编译),
visitor子类是变化的

六:要点总结

(一)Vistor模式通过所谓的双重分发(double dispatch)来实现在不更改(不添加新的操作-编译时)Element类层次结构的前提下,在运行时透明地为类层次结构上的各个类动态添加新的操作(支持变化)。

(二)所谓双重分发即Vistor模式中间包括了两个多态分发(注意其中的多态机制):第一个accept方法的多态解析;第二个为visitElementX方法的多态辨析。

(三)Visitor模式最大的缺点在于扩展类层次结构(增添新的Element子类),会导致Visitor类的改变。因此Visitor模式适用于“Element类层次结构稳定,而其中的操作却进场面临频繁改动”。 

 

以上是关于设计模式---行为变化模式之访问器模式(Visitor)的主要内容,如果未能解决你的问题,请参考以下文章

设计模式——行为型模式之迭代器模式

行为模式之迭代器模式

行为型模式之迭代器模式

25行为型模式之迭代器模式

行为型设计模式之迭代器模式

20.(行为型模式)java设计模式之迭代器模式