当前位置: 首页 > news >正文

C++ 访问者模式详解

访问者模式(Visitor Pattern)是一种行为设计模式,它允许你将算法对象结构分离,使得可以在不修改现有对象结构的情况下定义新的操作。

核心概念

设计原则

访问者模式遵循以下设计原则:

  1. 开闭原则:可以添加新访问者而不修改元素类

  2. 单一职责原则:将相关行为集中到访问者中

  3. 双重分发:利用双分派技术实现动态绑定

主要优点

  1. 算法集中:将相关行为集中在一个访问者对象中

  2. 灵活扩展:容易添加新的操作

  3. 跨类操作:可以对不同类的对象执行统一操作

  4. 数据分离:将数据结构与数据操作分离

模式结构

主要组件

  1. Visitor(访问者接口)

    • 为每个具体元素类声明访问操作

  2. ConcreteVisitor(具体访问者)

    • 实现每个访问操作

  3. Element(元素接口)

    • 定义accept方法接受访问者

  4. ConcreteElement(具体元素)

    • 实现accept方法

  5. ObjectStructure(对象结构)

    • 维护元素集合

    • 提供遍历元素的方法

完整代码示例

#include <iostream>
#include <vector>
#include <memory>
#include <string>// 前向声明
class ConcreteElementA;
class ConcreteElementB;// ==================== 访问者接口 ====================
class Visitor {
public:virtual void visit(ConcreteElementA* element) = 0;virtual void visit(ConcreteElementB* element) = 0;virtual ~Visitor() = default;
};// ==================== 元素接口 ====================
class Element {
public:virtual void accept(Visitor* visitor) = 0;virtual ~Element() = default;
};// ==================== 具体元素A ====================
class ConcreteElementA : public Element {std::string name_;
public:explicit ConcreteElementA(const std::string& name) : name_(name) {}void accept(Visitor* visitor) override {visitor->visit(this);}std::string getName() const { return name_; }// 元素特有的操作std::string operationA() const {return "元素A特有操作";}
};// ==================== 具体元素B ====================
class ConcreteElementB : public Element {int value_;
public:explicit ConcreteElementB(int value) : value_(value) {}void accept(Visitor* visitor) override {visitor->visit(this);}int getValue() const { return value_; }// 元素特有的操作std::string operationB() const {return "元素B特有操作";}
};// ==================== 具体访问者1 ====================
class ConcreteVisitor1 : public Visitor {
public:void visit(ConcreteElementA* element) override {std::cout << "访问者1访问" << element->getName() << ": " << element->operationA() << std::endl;}void visit(ConcreteElementB* element) override {std::cout << "访问者1访问元素B(值=" << element->getValue() << "): " << element->operationB() << std::endl;}
};// ==================== 具体访问者2 ====================
class ConcreteVisitor2 : public Visitor {
public:void visit(ConcreteElementA* element) override {std::cout << "访问者2记录元素A: " << element->getName() << std::endl;}void visit(ConcreteElementB* element) override {std::cout << "访问者2处理元素B值: " << element->getValue() * 2 << std::endl;}
};// ==================== 对象结构 ====================
class ObjectStructure {std::vector<std::unique_ptr<Element>> elements_;public:void addElement(std::unique_ptr<Element> element) {elements_.push_back(std::move(element));}void accept(Visitor* visitor) {for (const auto& element : elements_) {element->accept(visitor);}}
};// ==================== 客户端代码 ====================
int main() {std::cout << "=== 访问者模式演示 ===" << std::endl;// 创建对象结构ObjectStructure structure;structure.addElement(std::make_unique<ConcreteElementA>("测试元素A"));structure.addElement(std::make_unique<ConcreteElementB>(42));structure.addElement(std::make_unique<ConcreteElementA>("另一个元素A"));structure.addElement(std::make_unique<ConcreteElementB>(100));// 创建访问者ConcreteVisitor1 visitor1;ConcreteVisitor2 visitor2;// 使用不同访问者访问结构std::cout << "\n使用访问者1:" << std::endl;structure.accept(&visitor1);std::cout << "\n使用访问者2:" << std::endl;structure.accept(&visitor2);return 0;
}

模式变体

1. 带返回值的访问者

class ComputingVisitor : public Visitor {int total_ = 0;
public:void visit(ConcreteElementA* element) override {total_ += element->getName().length();}void visit(ConcreteElementB* element) override {total_ += element->getValue();}int getTotal() const { return total_; }
};// 使用示例
ComputingVisitor computingVisitor;
structure.accept(&computingVisitor);
std::cout << "计算总和: " << computingVisitor.getTotal() << std::endl;

2. 基于模板的访问者

template <typename... Types>
class GenericVisitor;template <typename T>
class GenericVisitor<T> {
public:virtual void visit(T* element) = 0;virtual ~GenericVisitor() = default;
};template <typename T, typename... Types>
class GenericVisitor<T, Types...> : public GenericVisitor<Types...> {
public:using GenericVisitor<Types...>::visit;virtual void visit(T* element) = 0;
};// 定义元素接口
class Element {
public:template <typename... Types>void accept(GenericVisitor<Types...>* visitor) {if (auto* v = dynamic_cast<GenericVisitor<ConcreteElementA, ConcreteElementB>*>(visitor)) {if (auto* elem = dynamic_cast<ConcreteElementA*>(this)) {v->visit(elem);} else if (auto* elem = dynamic_cast<ConcreteElementB*>(this)) {v->visit(elem);}}}
};

实际应用场景

  1. 编译器设计:语法树的不同遍历方式(类型检查、代码生成等)

  2. 文档处理:对文档结构的不同操作(渲染、字数统计等)

  3. UI组件:对复杂UI结构的操作(样式应用、布局计算等)

  4. 游戏开发:游戏对象的不同处理(渲染、物理计算等)

  5. 财务系统:财务数据的不同分析(税务计算、报表生成等)

http://www.xdnf.cn/news/360901.html

相关文章:

  • Redis面试题
  • 力扣26——删除有序数组中的重复项
  • 【推荐笔记工具】思源笔记 - 隐私优先的个人知识管理系统,支持 Markdown 排版、块级引用和双向链接
  • Qt 的原理及使用(1)——qt的背景及安装
  • 在另一个省发布抖音作品,IP属地会随之变化吗?
  • 【数据结构】1. 时间/空间复杂度
  • 2025数维杯数学建模A题完整论文模型代码:空中芭蕾
  • SpringBoot统一功能处理
  • 13.原生测试框架Unittest解决用例组织问题 与测试套件的使用
  • H5 移动端适配最佳实践落地指南。
  • 影楼精修-牙齿美型修复算法解析
  • 数据类型:List
  • robotframe启动ride.py
  • C++ Dll创建与调用 查看dll函数 MFC 单对话框应用程序(EXE 工程)改为 DLL 工程
  • C#学习——继承、封装、多态
  • 安科瑞DJSF1352-RN直流电能表的技术特点与应用
  • ZYNQ笔记(十九):VDMA VGA 输出分辨率可调
  • 各类音频放大器电路原理简析
  • MSF 生成不同的木马 msfvenom 框架命令
  • html object标签介绍(用于嵌入外部资源通用标签)(已不推荐使用deprecated,建议使用img、video、audio标签)
  • Nx与Monorepo
  • 【软件测试】测试用例的概念与常见测试的模型
  • Django ORM: values() 和 annotate() 方法详解
  • 2025-05-09 提示学习概念
  • Edu教育邮箱申请2025年5月
  • 【Lattice FPGA 开发】Diamond在线调试Reveal逻辑乱跳的解决
  • lambda 表达式
  • 摄像头模组高像素模组
  • AI模型蒸馏技术在微控制器上的内存占用与精度平衡实践
  • Java中的反射