访问器模式 Visitor

“行为变化”模式

  • 在组件的构建过程中,组件行为的变化经常导致组件本身剧烈的变化。“行为变化”模式将组件的行为和组件本身进行解耦,从而支持组件行为的变化,实现两者之间的松耦合。
  • 典型模式
    1· Command
    2. Visitor

动机(Motivation)

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

模式定义

表示一个作用于某对象结构中的各元素的操作。使得可以在不改变(稳定)各元素的类的前提下定义(扩展)作用于这些元素的新操作(变化)。——《设计模式》GoF

代码示例


#include <iostream>
#include <string>

using namespace std;

class Visitor;

class Element
{
public:
    virtual void accept(Visitor& visitor) = 0; //第一次多态辨析
    virtual void doSomething() = 0;
    virtual ~Element() {}
};

class Visitor {
public:
    virtual void visitElementA(Element& element) = 0;
    virtual void visitElementB(Element& element) = 0;
    virtual ~Visitor() {}
};


/**************************************/

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

    virtual void doSomething() override
    {
        std::cout << "Hello, this is ElementA do something." << std::endl;;
    }
};


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

    virtual void doSomething() override
    {
        std::cout << "Hello, this is ElementB do something." << std::endl;;
    }
};

//==================================  以上稳定

//扩展1
class Visitor1 : public Visitor {
public:
    virtual void visitElementA(Element& element) override
    {
        cout << "Visitor1 is processing ElementA" << endl;
        element.doSomething();
    }
    virtual  void visitElementB(Element& element) override {
        cout << "Visitor1 is processing ElementB" << endl;
        element.doSomething();
    }
};

//扩展2
class Visitor2 : public Visitor {
public:
    virtual  void visitElementA(Element& element) override {
        cout << "Visitor2 is processing ElementA" << endl;
        element.doSomething();
    }
    virtual void visitElementB(Element& element) override {
        cout << "Visitor2 is processing ElementB" << endl;
        element.doSomething();
    }
};


int main()
{
    Visitor1 visitor1;
    Visitor2 visitor2;
    ElementB elementB;
    elementB.accept(visitor1);// double dispatch    多态辩析

    ElementA elementA;
    elementA.accept(visitor2);

    getchar();
    return 0;
}

输出:

Visitor1 is processing ElementB
Hello, this is ElementB do something.
Visitor2 is processing ElementA
Hello, this is ElementA do something.

accept 函数很重要。

类图

ConcreteElementA ConcreteElementA 也必须要稳定。前提, Vistor 要知道有多少个 Element 子类(这个实际可能很难保证,这也就是它的缺点了)。
若是新增一个 Element 派生类,Vistor 基类的内部代码要改变,就违背了模式的原则,开闭原则。

所以这个模式的前提条件非常苛刻,要求Element子类层次结构稳定。

要点总结

  • Visitor模式通过所谓双重分发(double dispatch)来实现在不更改(不添加新的操作-编译时)Element类层次结构的前提下,在运行时透明地为类层次结构上的各个类动态添加新的操作(支持变化)。
  • 所谓双重分发即Visitor模式中间包括了两个多态分发(注意其中的。多态机制):第一个为accept方法的多态辨析;第二个为visitElementX方法的多态辨析。
  • Visitor模式的最大缺点在于扩展类层次结构(增添新的Element子a。类),会导致Visitor类的改变。因此Vistor模式适用于“Element类。层次结构稳定,而其中的操作却经常面临频繁改动”。

一般不怎么用,因为前提条件太苛刻。要用就用的比较重。




参考:GeekBand

posted @   double64  阅读(48)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
点击右上角即可分享
微信分享提示