访问者模式(Visitor Pattern)是一种行为设计模式,它允许你将算法 与对象结构分离,使得可以在不修改现有对象结构的情况下定义新的操作。
核心概念
设计原则
访问者模式遵循以下设计原则:
-
开闭原则:可以添加新访问者而不修改元素类
-
单一职责原则:将相关行为集中到访问者中
-
双重分发:利用双分派技术实现动态绑定
主要优点
-
算法集中:将相关行为集中在一个访问者对象中
-
灵活扩展:容易添加新的操作
-
跨类操作:可以对不同类的对象执行统一操作
-
数据分离:将数据结构与数据操作分离
模式结构
主要组件
-
Visitor(访问者接口)
- 为每个具体元素类声明访问操作
-
ConcreteVisitor(具体访问者)
- 实现每个访问操作
-
Element(元素接口)
- 定义accept方法接受访问者
-
ConcreteElement(具体元素)
- 实现accept方法
-
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);
}
}
}
};
实际应用场景
-
编译器设计:语法树的不同遍历方式(类型检查、代码生成等)
-
文档处理:对文档结构的不同操作(渲染、字数统计等)
-
UI组件:对复杂UI结构的操作(样式应用、布局计算等)
-
游戏开发:游戏对象的不同处理(渲染、物理计算等)
-
财务系统:财务数据的不同分析(税务计算、报表生成等)