访问者模式用于分离稳定的数据结构与易变的操作,通过双分派实现开闭原则;核心角色为Visitor(定义visit重载)、Element(实现accept)和ObjectStructure(遍历元素);需注意const正确性与新增类型对Visitor的侵入性。
访问者模式(Visitor Pattern)在 C++ 中主要用于分离数据结构与作用于其上的操作,特别适合当对象结构稳定但操作频繁变化的场景。它通过双分派机制,让新增操作无需修改现有类,符合开闭原则。
Visitor 模式包含三个关键角色:
C++ 不原生支持双分派,访问者模式靠两次虚函数调用模拟:第一次是 Element::accept() 的虚调用(确定元素类型),第二次是 Visitor::visit(ElementType&) 的重载解析(确定操作类型)。需注意:
Visitor 基类:
struct Visitor {
virtual void visit(const Circle&) = 0;
virtual void visit(const Rectangle&) = 0;
virtual ~Visitor() = default;
};
Element 基类及实现:
struct Element {
virtual void accept(Visitor&) const = 0;
virtual ~Element() = default;
};
struct Circle : Element {
double r;
void accept(Visitor& v) const override { v.visit(*this); }
};
struct Rectangle : Element {
double w, h;
void accept(Visitor& v) const override { v.visit(*this); }
};
具体访问者与使用:
struct PrintVisitor : Visitor {
void visit(const Circle& c) const override { cout << "Circle(r=" << c.r << ")"; }
void visit(const Rectangle& r) const override { cout << "Rect(w=" << r.w << ",h=" << r.h << ")"; }
};
// 使用
vector> shapes = {make_shared(Circle{2.0}), make_shared(Rectangle{3.0,4.0})};
PrintVisitor printer;
for (const auto& e : shapes) e->accept(printer);
适合结构稳定(如 AST、GUI 控件树、几何图元集合)、操作多变(渲染、导出、校验、优化)的情况。但要注意:
似效果(更轻量),但失去运行时动态添加访问者的能力。基本上就这些。用好访问者,关键在想清楚“谁变谁不变”——结构不变、行为常变时,它很踏实。