模式特点
表示一个作用于某对象结构中各元素的操作。访问者模式使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。
- 将数据结构与数据操作分离
- 新增操作只需新增访问者,无需修改元素类
- 使用双重分派(double dispatch)机制
- 适合数据结构稳定但操作多变的场景
类图
应用场景
- Qt 中 QTextDocument 的遍历操作:访问不同类型节点
- 编译器 AST 树:对语法树节点执行不同操作(语义检查、代码生成)
- 示教器运动轨迹:对运动指令执行编译、仿真、导出等操作
- 序列化框架:对对象结构进行 XML/JSON 等多种格式序列化
- UI 树遍历:对 QWidget 树执行渲染、事件分发、布局等操作
示例代码(C++)
// 前向声明 class MoveInstruction; class IOInstruction; class WaitInstruction; // 访问者接口 class InstructionVisitor { public: virtual void visit(MoveInstruction&) = 0; virtual void visit(IOInstruction&) = 0; virtual void visit(WaitInstruction&) = 0; virtual ~InstructionVisitor() = default; }; // 元素基类 class Instruction { public: virtual void accept(InstructionVisitor& v) = 0; virtual ~Instruction() = default; }; // 具体元素 - 运动指令 class MoveInstruction : public Instruction { public: double x, y, z; void accept(InstructionVisitor& v) override { v.visit(*this); } // 双重分派 }; // 具体元素 - IO 指令 class IOInstruction : public Instruction { public: int port; bool value; void accept(InstructionVisitor& v) override { v.visit(*this); } }; // 具体访问者 - 代码生成 class CodeGenVisitor : public InstructionVisitor { public: void visit(MoveInstruction& m) override { std::cout << "生成: MoveTo(" << m.x << "," << m.y << "," << m.z << ")" << std::endl; } void visit(IOInstruction& io) override { std::cout << "生成: SetIO(" << io.port << "," << io.value << ")" << std::endl; } void visit(WaitInstruction&) override { std::cout << "生成: Wait" << std::endl; } }; // 使用:不修改指令类即可新增操作(如仿真、导出 XML) std::vector<Instruction*> program; CodeGenVisitor visitor; for (auto* inst : program) inst->accept(visitor);