设计模式——访问者模式

访问者模式(Visitor)

   表示作用于某个对象结构中各元素的操作。它使你可以在不改变各元素类的前提下定义作用于这些元素的新操作。

代码举例

c++ 复制代码
#include <iostream>
#include <string>
#include <list>
#include <memory>

using namespace std;

class Action;

// 人的抽象类(Element)
class Person
{
public:
    virtual void Accept(shared_ptr<Action> visitor) = 0;
};

// 注意forward declaration怎么写
class Man;
class Woman;

// 状态的抽象类(Visitor)
class Action
{
public:
    virtual void GetManConclusion(const Man& concreteElementA) = 0;
    virtual void GetWomanConclusion(const Woman& concreteElementA) = 0;
};

// 具体状态类
class Success : public Action
{
public:
    void GetManConclusion(const Man& concreteElementA) override
    {
        cout << "男人成功" << "时, 背后多半有一个伟大的女人。" << endl;
    }

    void GetWomanConclusion(const Woman& concreteElementB) override
    {
        cout << "女人成功" << "时, 背后大多有一个不成功的男人。" << endl;
    }
};

class Failing : public Action
{
public:
    void GetManConclusion(const Man& concreteElementA) override
    {
        cout << "男人失败"  << "时, 蒙头喝酒,谁也不劝。" << endl;
    }

    void GetWomanConclusion(const Woman& concreteElementB) override
    {
        cout << "女人失败" <<  "时, 眼泪汪汪,谁也劝不了。" << endl;
    }
};

class Amativeness : public Action
{
public:
    void GetManConclusion(const Man& concreteElementA) override
    {
        cout << "男人恋爱" << "时, 凡事不懂也要装懂。" << endl;
    }

    void GetWomanConclusion(const Woman& concreteElementB) override
    {
        cout << "女人恋爱" << "时, 遇事懂也装不懂。" << endl;
    }
};

// 具体的Person, ConcreteElement
class Man : public Person
{
public:
    void Accept(shared_ptr<Action> visitor) override
    {
        visitor->GetManConclusion(*this);
    }
};

class Woman : public Person
{
public:
    void Accept(shared_ptr<Action> visitor) override
    {
        visitor->GetWomanConclusion(*this);
    }
};

// ObjectStructure类,提供一个高层的接口以允许枚举访问所有元素
class ObjectStructure
{
public:
    // 增加
    void Attach(shared_ptr<Person> element)
    {
        elements_.push_back(element);
    }

    // 移除
    void Detach(shared_ptr<Person> element)
    {
        elements_.remove(element);
    }

    // 打印
    void Display(shared_ptr<Action> visitor)
    {
        for (auto& e : elements_)
        {
            e->Accept(visitor);
        }
    }

private:
    list<shared_ptr<Person>> elements_;
};

// 客户端代码
void Client()
{
    ObjectStructure o;
    o.Attach(make_shared<Man>());
    o.Attach(make_shared<Woman>());

    // 成功的反应
    auto v1 = make_shared<Success>();
    o.Display(v1);

    // 失败的反应
    auto v2 = make_shared<Failing>();
    o.Display(v2);

    // 恋爱的反应
    auto v3 = make_shared<Amativeness>();
    o.Display(v3);
}

int main()
{
    Client();

    return 0;
}

输出为

复制代码
男人成功时, 背后多半有一个伟大的女人。
女人成功时, 背后大多有一个不成功的男人。
男人失败时, 蒙头喝酒,谁也不劝。
女人失败时, 眼泪汪汪,谁也劝不了。
男人恋爱时, 凡事不懂也要装懂。
女人恋爱时, 遇事懂也装不懂。

   由于使用了双分派,当我们需要添加一个新的状态的时候,只需要增加一个状态的子类,而不需要改动其他类的代码。

适用条件

   * 访问者模式适用于数据结构相对稳定的系统。例如上面的人分为男人和女人

   * 访问者模式将数据结构和作用于结构上的操作之间的耦合分开,使得操作可以相对自由的演化。

   * 增加新的操作实际上就是增加了数据结构的一个访问者。

   * 相应的,这个模式的缺点就是不方便增加新的数据结构。

相关推荐
lulu121654407811 小时前
OpenRouter Fusion 多模型融合架构深度拆解:预算级模型组团打平 Fable 5,多模型协作才是 AGI 的正确打开方式?
java·人工智能·架构·ai编程·agi
雨辰AI11 小时前
生产级实测:SpringBoot3 + 达梦数据库接口从 200ms 优化至 20ms 完整调优指南
java·数据库·spring boot·后端·政务
(Charon)11 小时前
【C++ 面试高频:内存管理、RAII 和智能指针详解】
java·开发语言·word
凡人叶枫11 小时前
Effective C++ 条款39:明智而审慎地使用 private 继承
java·数据库·c++·嵌入式开发
轻刀快马12 小时前
跨越软硬件的共鸣(二):从 Cache 写策略看 Redis 与 DB 的一致性博弈
java·开发语言·redis·计算机组成原理
折哥的程序人生 · 物流技术专研12 小时前
Java 23 种设计模式:从踩坑到精通 | 装饰器模式 —— 比继承更灵活的扩展方式,你用过吗?
java·装饰器模式·java面试·结构型模式·java设计模式·javaio·从踩坑到精通
lili001212 小时前
2026 企业 AI 选型新范式:OpenRouter Fusion 证明多模型融合性价比远超单模型,企业该如何重构技术栈? - 微元算力(weytoken)
java·人工智能·python·重构·ai编程
shushangyun_12 小时前
汽车服务行业B2B平台+AI解决方案哪家专业:2026年最新测评
java·运维·网络·数据库·人工智能·汽车
A.说学逗唱的Coke12 小时前
【大模型专题】Spring AI Alibaba × Skill 整合实战:让 AI 真正“会干活
java·人工智能·spring
大黄说说12 小时前
深入理解 Go 协程 Goroutine:并发编程的核心精髓
java·数据库·python