📕目录

class 卑微码农:
def __init__(self):
self.技能 = ['能读懂十年前祖传代码', '擅长用Ctrl+C/V搭建世界', '信奉"能跑就别动"的玄学']
self.发量 = 100 # 初始发量
self.咖啡因耐受度 = '极限'
def 修Bug(self, bug):
try:
# 试图用玄学解决问题
if bug.严重程度 == '离谱':
print("这一定是环境问题!")
else:
print("让我看看是谁又没写注释...哦,是我自己。")
except Exception as e:
# 如果try块都救不了,那就...
print("重启一下试试?")
self.发量 -= 1 # 每解决一个bug,头发-1
# 实例化一个我
我 = 卑微码农()
前言

在C++开发的江湖里,我们总会遇到这样的困境:一个稳定的对象结构(比如电商系统的商品体系、编译器的抽象语法树),却要频繁添加各种跨对象的操作(比如统计价格、导出数据、权限校验)。如果直接在对象类里堆代码,很快就会陷入"修改一个类,牵一发而动全身"的泥潭——这就是典型的"数据结构与操作耦合"绝症。
今天要聊的访问者模式,就是专治这种绝症的良方。它像一位灵活的巡检员,能在不改动对象本身的前提下,对对象结构里的每个元素执行定制化操作。本文会从实际开发场景出发,用C++代码手把手带你吃透访问者模式,从基础结构到进阶优化,再到避坑指南,全流程无死角解析。
一、为什么需要访问者模式?先看一个真实痛点

假设我们在开发一个电商后台的商品管理系统,系统中有三种核心商品类型:电子产品(手机、电脑)、服装(T恤、裤子)、食品(面包、牛奶)。每种商品都有名称、价格等基础属性,现在需要实现两个功能:
-
统计所有商品的总价(财务对账用)
-
生成商品的JSON导出数据(前端展示用)
如果不用设计模式,大多数人会这么写代码(新手常见写法):
#include <iostream>
#include <vector>
#include <string>
#include <nlohmann/json.hpp> // 假设使用nlohmann/json库
using namespace std;
using json = nlohmann::json;
// 电子产品类
class ElectronicProduct {
private:
string name;
double price;
// 电子产品特有属性:保修年限
int warrantyYears;
public:
ElectronicProduct(string n, double p, int w) : name(n), price(p), warrantyYears(w) {}
// 获取基础属性
string getName() const { return name; }
double getPrice() const { return price; }
int getWarrantyYears() const { return warrantyYears; }
// 功能1:计算价格(直接集成)
double calculatePrice() const { return price; }
// 功能2:生成JSON(直接集成)
json toJson() const {
return json{{"type", "electronic"}, {"name", name}, {"price", price}, {"warranty", warrantyYears}};
}
};
// 服装类
class Clothing {
private:
string name;
double price;
// 服装特有属性:尺码
string size;
public:
Clothing(string n, double p, string s) : name(n), price(p), size(s) {}
string getName() const { return name; }
double getPrice() const { return price; }
string getSize() const { return size; }
// 同样集成两个功能
double calculatePrice() const { return price; }
json toJson() const {
return json{{"type", "clothing"}, {"name", name}, {"price", price}, {"size", size}};
}
};
// 食品类
class Food {
private:
string name;
double price;
// 食品特有属性:保质期
int shelfLifeDays;
public:
Food(string n, double p, int s) : name(n), price(p), shelfLifeDays(s) {}
string getName() const { return name; }
double getPrice() const { return price; }
int getShelfLifeDays() const { return shelfLifeDays; }
double calculatePrice() const { return price; }
json toJson() const {
return json{{"type", "food"}, {"name", name}, {"price", price}, {"shelfLife", shelfLifeDays}};
}
};
// 商品管理类(对象结构)
class ProductManager {
private:
vector<ElectronicProduct*> electronics;
vector<Clothing*> clothings;
vector<Food*> foods;
public:
// 添加商品的方法(三种类型各一个)
void addElectronic(ElectronicProduct* ep) { electronics.push_back(ep); }
void addClothing(Clothing* c) { clothings.push_back(c); }
void addFood(Food* f) { foods.push_back(f); }
// 统计总价(需要遍历所有类型)
double calculateTotalPrice() {
double total = 0;
for (auto ep : electronics) total += ep->calculatePrice();
for (auto c : clothings) total += c->calculatePrice();
for (auto f : foods) total += f->calculatePrice();
return total;
}
// 导出所有商品JSON(同样遍历所有类型)
json exportAllJson() {
json result = json::array();
for (auto ep : electronics) result.push_back(ep->toJson());
for (auto c : clothings) result.push_back(c->toJson());
for (auto f : foods) result.push_back(f->toJson());
return result;
}
};
// 客户端代码
int main() {
ProductManager pm;
// 添加商品
pm.addElectronic(new ElectronicProduct("iPhone 15", 9999, 1));
pm.addClothing(new Clothing("Cotton T-shirt", 99, "M"));
pm.addFood(new Food("Milk Bread", 8.8, 3));
// 统计总价
cout << "Total Price: " << pm.calculateTotalPrice() << endl;
// 导出JSON
cout << "All Products JSON: " << pm.exportAllJson().dump(4) << endl;
// 这里省略内存释放代码,实际开发需注意
return 0;
}
这段代码能跑通,但如果你是维护者,很快会发现三个致命问题:
1. 功能扩展灾难:如果新增"生成Excel报表"功能,需要修改ElectronicProduct、Clothing、Food三个类,再修改ProductManager——违反"开闭原则"(对扩展开放,对修改关闭)。
2. 代码冗余混乱:统计价格、导出数据这些跨对象的操作,被分散在各个商品类中,后续排查bug或修改逻辑时,需要在多个类之间跳来跳去。
3. 对象结构僵化:ProductManager中为每种商品类型都写了容器和遍历逻辑,新增商品类型(比如化妆品)时,需要大幅修改ProductManager的代码。
而访问者模式的核心思想,就是把"数据结构"和"操作"彻底分离——让商品类只保留自身属性和接受访问的接口,把统计、导出这些操作封装成独立的"访问者"类。这样新增操作时,只需要加新的访问者,不用改商品类;商品类新增时,也只需扩展访问者接口,逻辑清晰且符合开闭原则。
二、访问者模式的核心结构:5个角色拆解

访问者模式是一种行为型设计模式,它的核心是通过"双重分派"机制,实现访问者对不同元素的差异化操作。官方定义的5个角色看似抽象,结合上面的电商场景一对应就很容易理解:
| 角色名称 | 核心职责 | 电商场景对应 |
|---|---|---|
| 抽象访问者(Visitor) | 定义访问所有具体元素的接口,为每种元素类型声明一个visit方法 | 声明访问电子产品、服装、食品的接口(visitElectronic等) |
| 具体访问者(ConcreteVisitor) | 实现抽象访问者的接口,定义对每种元素的具体操作逻辑 | 统计总价访问者(实现计算每种商品价格的逻辑)、JSON导出访问者(实现每种商品的JSON转换) |
| 抽象元素(Element) | 声明接受访问者的接口(accept方法),将自身作为参数传给访问者 | 商品抽象类(声明accept方法) |
| 具体元素(ConcreteElement) | 实现抽象元素的accept方法,调用访问者对应的visit方法 | 电子产品、服装、食品类(实现accept方法,调用visitor->visit(this)) |
| 对象结构(ObjectStructure) | 管理元素集合,提供遍历接口供访问者访问所有元素 | 商品管理类(管理所有商品,提供accept方法让访问者遍历访问) |
这5个角色的协作流程可以总结为三句话:
-
对象结构持有所有具体元素,当需要执行操作时,接收一个具体访问者
-
对象结构遍历所有元素,调用每个元素的accept方法,并将访问者传入
-
每个元素的accept方法调用访问者对应的visit方法,完成访问者对该元素的操作
这里的关键是"双重分派":第一次分派是对象结构调用元素的accept方法(确定元素类型),第二次分派是元素调用访问者的visit方法(确定访问者类型)。通过这两次分派,就能精准匹配"访问者-元素"的组合,执行对应的操作。
三、C++实战:用访问者模式重构电商商品系统

下面我们用访问者模式重构开篇的电商系统,解决代码耦合问题。整个重构过程分四步走,每一步都有完整代码和注释,新手也能轻松跟上。
第一步:定义抽象元素和抽象访问者(核心接口)
首先定义商品抽象类(抽象元素)和访问者抽象类(抽象访问者)。抽象元素必须包含accept方法,用于接收访问者;抽象访问者必须为每种具体商品类型定义visit方法。
#include <iostream>
#include <vector>
#include <string>
#include <nlohmann/json.hpp>
#include <memory> // 用于智能指针,避免内存泄漏
using namespace std;
using json = nlohmann::json;
// 前向声明:抽象访问者需要知道具体元素类型,避免循环依赖
class ElectronicProduct;
class Clothing;
class Food;
// 抽象访问者(Visitor):定义访问所有商品的接口
class ProductVisitor {
public:
// 纯虚函数,必须由具体访问者实现
// 为每种商品类型声明一个visit方法
virtual void visit(ElectronicProduct& product) = 0;
virtual void visit(Clothing& product) = 0;
virtual void visit(Food& product) = 0;
// 虚析构函数,确保子类析构时能正确调用
virtual ~ProductVisitor() = default;
};
// 抽象元素(Element):商品抽象类
class Product {
public:
// 接受访问者的核心方法
virtual void accept(ProductVisitor& visitor) = 0;
// 商品通用属性(封装)
virtual string getName() const = 0;
virtual double getPrice() const = 0;
virtual ~Product() = default;
};
这里有两个关键注意点:
-
前向声明:由于抽象访问者的visit方法参数是具体商品类型,而具体商品类型又依赖抽象访问者,所以需要用前向声明打破循环依赖。
-
智能指针:后续使用shared_ptr管理对象,避免手动释放内存的麻烦,这是C++现代开发的最佳实践。
第二步:实现具体元素(三种商品类型)
具体商品类继承自Product抽象类,实现accept方法和自身特有属性。accept方法的实现非常固定,就是调用访问者对应的visit方法,并将自身作为参数传入——这是触发双重分派的关键一步。
// 具体元素1:电子产品
class ElectronicProduct : public Product {
private:
string name;
double price;
int warrantyYears; // 特有属性:保修年限
public:
ElectronicProduct(string n, double p, int w)
: name(n), price(p), warrantyYears(w) {}
// 实现accept方法:调用访问者的visit(ElectronicProduct)
void accept(ProductVisitor& visitor) override {
visitor.visit(*this); // 把自身传给访问者
}
// 实现通用属性接口
string getName() const override { return name; }
double getPrice() const override { return price; }
// 特有属性的访问接口(供访问者使用)
int getWarrantyYears() const { return warrantyYears; }
};
// 具体元素2:服装
class Clothing : public Product {
private:
string name;
double price;
string size; // 特有属性:尺码
public:
Clothing(string n, double p, string s)
: name(n), price(p), size(s) {}
void accept(ProductVisitor& visitor) override {
visitor.visit(*this);
}
string getName() const override { return name; }
double getPrice() const override { return price; }
string getSize() const { return size; }
};
// 具体元素3:食品
class Food : public Product {
private:
string name;
double price;
int shelfLifeDays; // 特有属性:保质期(天)
public:
Food(string n, double p, int s)
: name(n), price(p), shelfLifeDays(s) {}
void accept(ProductVisitor& visitor) override {
visitor.visit(*this);
}
string getName() const override { return name; }
double getPrice() const override { return price; }
int getShelfLifeDays() const { return shelfLifeDays; }
};
对比重构前的代码,现在的商品类变得非常"纯粹"——只包含自身属性和接受访问的接口,没有任何统计、导出等业务逻辑。这就是访问者模式"分离数据与操作"的核心体现。
第三步:实现具体访问者(统计、导出功能)
接下来把统计总价和导出JSON这两个功能,分别封装成两个具体访问者类。每个访问者实现抽象访问者的所有visit方法,针对不同商品类型编写差异化逻辑。
// 具体访问者1:统计总价访问者
class TotalPriceVisitor : public ProductVisitor {
private:
double totalPrice; // 累积状态:总价格
public:
TotalPriceVisitor() : totalPrice(0.0) {}
// 访问电子产品:累加价格
void visit(ElectronicProduct& product) override {
totalPrice += product.getPrice();
// 可以添加电子产品特有的逻辑,比如高端电子产品加税
if (product.getPrice() > 5000) {
totalPrice += product.getPrice() * 0.05; // 5%税
}
}
// 访问服装:直接累加价格
void visit(Clothing& product) override {
totalPrice += product.getPrice();
}
// 访问食品:累加价格,可添加临期食品折扣逻辑
void visit(Food& product) override {
double price = product.getPrice();
if (product.getShelfLifeDays() <= 1) {
price *= 0.5; // 临期食品5折
}
totalPrice += price;
}
// 获取统计结果
double getTotalPrice() const {
return totalPrice;
}
// 重置统计状态(方便重复使用)
void reset() {
totalPrice = 0.0;
}
};
// 具体访问者2:JSON导出访问者
class JsonExportVisitor : public ProductVisitor {
private:
json result; // 累积状态:导出的JSON数据
public:
JsonExportVisitor() : result(json::array()) {}
// 访问电子产品:生成包含保修信息的JSON
void visit(ElectronicProduct& product) override {
json item = {
{"type", "electronic"},
{"name", product.getName()},
{"price", product.getPrice()},
{"warranty_years", product.getWarrantyYears()}
};
result.push_back(item);
}
// 访问服装:生成包含尺码的JSON
void visit(Clothing& product) override {
json item = {
{"type", "clothing"},
{"name", product.getName()},
{"price", product.getPrice()},
{"size", product.getSize()}
};
result.push_back(item);
}
// 访问食品:生成包含保质期的JSON
void visit(Food& product) override {
json item = {
{"type", "food"},
{"name", product.getName()},
{"price", product.getPrice()},
{"shelf_life_days", product.getShelfLifeDays()}
};
result.push_back(item);
}
// 获取JSON结果(带格式化)
string getJsonString() const {
return result.dump(4); // 4个空格缩进,便于阅读
}
// 重置导出状态
void reset() {
result = json::array();
}
};
这里的亮点是"状态累积"——访问者可以在遍历过程中保存操作产生的状态(比如总价格、JSON数组),这在统计、汇总类场景中非常实用。而且每个访问者的逻辑独立封装,修改统计规则时只需改TotalPriceVisitor,不影响其他类。
第四步:实现对象结构(商品管理类)
对象结构的核心职责是管理所有商品对象,并提供一个accept方法,让访问者可以遍历访问所有商品。重构后的商品管理类不再需要为每种商品单独写容器,只需一个存储Product智能指针的向量即可。
// 对象结构(ObjectStructure):商品管理类
class ProductManager {
private:
// 存储商品抽象类的智能指针,支持所有商品类型
vector<shared_ptr<Product>> products;
public:
// 添加商品(支持任意商品类型,自动多态)
void addProduct(shared_ptr<Product> product) {
products.push_back(product);
}
// 核心方法:接受访问者,遍历所有商品让访问者访问
void accept(ProductVisitor& visitor) {
for (auto& product : products) {
// 调用商品的accept方法,触发访问者的visit
product->accept(visitor);
}
}
// 清空商品(可选)
void clearProducts() {
products.clear();
}
};
对比重构前的代码,现在的ProductManager变得异常简洁:新增商品类型时,不需要修改任何代码,直接addProduct即可;遍历逻辑也只需写一次,彻底解决了对象结构僵化的问题。
第五步:客户端调用(测试重构效果)
客户端代码只需创建商品、访问者和对象结构,通过对象结构的accept方法触发访问者操作,逻辑清晰易懂。我们还可以轻松新增访问者(比如Excel导出访问者),无需修改现有代码。
int main() {
// 1. 创建对象结构(商品管理器)
ProductManager pm;
// 2. 添加商品(多态特性:子类指针赋给父类指针)
pm.addProduct(make_shared<ElectronicProduct>("iPhone 15", 9999, 1));
pm.addProduct(make_shared<Clothing>("Cotton T-shirt", 99, "M"));
pm.addProduct(make_shared<Food>("Milk Bread", 8.8, 3));
pm.addProduct(make_shared<Food>("Yogurt", 5.0, 1)); // 临期食品(保质期1天)
// 3. 统计总价:使用TotalPriceVisitor
TotalPriceVisitor priceVisitor;
pm.accept(priceVisitor); // 触发访问者遍历所有商品
cout << "=== 商品总价统计 ===" << endl;
cout << "Total Price (including tax and discount): " << priceVisitor.getTotalPrice() << endl;
cout << endl;
// 4. 导出JSON:使用JsonExportVisitor
JsonExportVisitor jsonVisitor;
pm.accept(jsonVisitor); // 触发访问者遍历所有商品
cout << "=== 商品JSON导出 ===" << endl;
cout << jsonVisitor.getJsonString() << endl;
// 5. 新增操作:无需修改现有类,直接加新访问者即可
// 比如新增ExcelExportVisitor,此处省略实现...
return 0;
}
运行结果如下(包含临期食品折扣和高端电子产品税):
=== 商品总价统计 ===
Total Price (including tax and discount): 10577.7
=== 商品JSON导出 ===
[
{
"name": "iPhone 15",
"price": 9999.0,
"type": "electronic",
"warranty_years": 1
},
{
"name": "Cotton T-shirt",
"price": 99.0,
"size": "M",
"type": "clothing"
},
{
"name": "Milk Bread",
"price": 8.8,
"shelf_life_days": 3,
"type": "food"
},
{
"name": "Yogurt",
"price": 5.0,
"shelf_life_days": 1,
"type": "food"
}
]
重构后的代码完美解决了开篇的三个问题:新增操作只需加访问者,商品类无需修改;操作逻辑集中在访问者中,无冗余;新增商品类型只需扩展访问者接口,对象结构无需改动。
四、访问者模式的进阶:变体与优化技巧

上面的基础实现虽然解决了核心问题,但在实际开发中还有一些场景需要优化。比如新增商品类型时,需要修改抽象访问者的接口,这违反了开闭原则。下面介绍两种C++中常用的访问者变体,解决这些痛点。
1. 反射优化访问者(解决元素扩展问题)
基础实现中,新增商品类型(如Cosmetic化妆品)时,需要修改ProductVisitor接口,添加visit(Cosmetic&)方法,这会导致所有具体访问者都要同步修改。利用C++的RTTI(运行时类型识别)特性,可以实现"动态访问者",无需修改接口即可支持新元素。
#include <typeinfo> // 用于typeid
// 反射式抽象访问者:无需为每种元素声明visit方法
class ReflectiveProductVisitor {
public:
virtual ~ReflectiveProductVisitor() = default;
// 核心方法:根据元素类型动态调用对应的visit方法
void visit(Product& product) {
// 通过typeid获取元素的实际类型
const type_info& type = typeid(product);
if (type == typeid(ElectronicProduct)) {
visitDynamic(dynamic_cast<ElectronicProduct&>(product));
} else if (type == typeid(Clothing)) {
visitDynamic(dynamic_cast<Clothing&>(product));
} else if (type == typeid(Food)) {
visitDynamic(dynamic_cast<Food&>(product));
} else {
// 处理未知类型(默认操作)
visitUnknown(product);
}
}
// 具体元素的访问方法(子类实现)
virtual void visitDynamic(ElectronicProduct& product) = 0;
virtual void visitDynamic(Clothing& product) = 0;
virtual void visitDynamic(Food& product) = 0;
// 未知元素的默认处理
virtual void visitUnknown(Product& product) {
cout << "Unknown product type: " << product.getName() << endl;
}
};
// 具体反射访问者:简化的统计访问者
class SimplePriceVisitor : public ReflectiveProductVisitor {
private:
double total;
public:
SimplePriceVisitor() : total(0) {}
void visitDynamic(ElectronicProduct& product) override {
total += product.getPrice();
}
void visitDynamic(Clothing& product) override {
total += product.getPrice();
}
void visitDynamic(Food& product) override {
total += product.getPrice();
}
double getTotal() const { return total; }
};
这种方式的优点是新增商品类型时,只需修改ReflectiveProductVisitor的visit方法,无需改动所有具体访问者;缺点是使用dynamic_cast有轻微性能开销,且类型判断依赖typeid,不如编译期检查严格。适合元素类型频繁新增的场景。
2. Lambda简化访问者(适合简单操作)
对于一些简单的临时操作,每次都创建一个具体访问者类太繁琐。可以利用C++11及以上的Lambda表达式,实现"匿名访问者",大幅简化代码。
#include <functional>
#include <unordered_map>
// Lambda访问者:通过注册Lambda表达式处理不同元素
class LambdaProductVisitor : public ProductVisitor {
private:
// 存储"元素类型信息 - Lambda处理函数"的映射
using ElectronicHandler = function<void(ElectronicProduct&)>;
using ClothingHandler = function<void(Clothing&)>;
using FoodHandler = function<void(Food&)>;
ElectronicHandler electronicHandler;
ClothingHandler clothingHandler;
FoodHandler foodHandler;
public:
// 注册各元素的处理函数
void onElectronic(ElectronicHandler handler) {
electronicHandler = handler;
}
void onClothing(ClothingHandler handler) {
clothingHandler = handler;
}
void onFood(FoodHandler handler) {
foodHandler = handler;
}
// 实现访问者接口,调用对应的Lambda
void visit(ElectronicProduct& product) override {
if (electronicHandler) electronicHandler(product);
}
void visit(Clothing& product) override {
if (clothingHandler) clothingHandler(product);
}
void visit(Food& product) override {
if (foodHandler) foodHandler(product);
}
};
// 客户端使用示例:临时统计食品数量
int main() {
ProductManager pm;
pm.addProduct(make_shared<Food>("Bread", 3.5, 7));
pm.addProduct(make_shared<Food>("Milk", 6.0, 5));
// 使用Lambda访问者统计食品数量
int foodCount = 0;
LambdaProductVisitor lambdaVisitor;
// 注册食品的处理逻辑(Lambda表达式)
lambdaVisitor.onFood([&foodCount](Food& product) {
foodCount++;
cout << "Found food: " << product.getName() << endl;
});
// 其他商品类型的处理逻辑可选注册
lambdaVisitor.onElectronic([](ElectronicProduct& product) {
// 空实现或默认处理
});
pm.accept(lambdaVisitor);
cout << "Total food count: " << foodCount << endl; // 输出2
return 0;
}
这种方式特别适合临时的、简单的操作,无需定义单独的访问者类,代码更紧凑。但对于复杂的、需要状态累积的操作,还是传统访问者模式更清晰。
五、访问者模式的利弊与适用场景

没有完美的设计模式,只有适合的场景。访问者模式的优缺点非常鲜明,实际开发中需要根据业务场景权衡使用。
核心优点
-
解耦数据与操作:元素类只保留自身数据,操作被封装在访问者中,符合单一职责原则。
-
扩展灵活:新增操作只需添加新访问者,无需修改元素类,完美符合开闭原则。
-
操作集中化:同一类操作的代码集中在一个访问者中,便于维护和调试(比如所有统计相关逻辑都在PriceVisitor中)。
-
支持复杂遍历:对象结构可以提供多种遍历方式(如深度优先、广度优先),访问者无需关心遍历细节。
主要缺点
-
元素扩展困难:新增元素类型时,需要修改所有访问者的接口和实现,违反开闭原则。
-
破坏封装性:访问者需要访问元素的内部属性,可能导致元素类暴露过多的访问接口。
-
依赖具体类型:访问者需要知道所有具体元素的类型,导致系统耦合度升高(抽象访问者依赖具体元素)。
-
学习成本高:双重分派机制相对抽象,新手不易理解和掌握。
黄金适用场景
1. 对象结构稳定,但操作频繁变化:比如编译器的抽象语法树(AST),语法树结构固定,但需要频繁添加词法分析、语义分析、代码生成等操作。
2. 需要对对象结构中的元素执行多种不相关的操作:比如文档编辑器中的元素(文本、图片、表格),需要执行导出PDF、统计字数、格式检查等操作。
3. 需要跨多个元素累积状态:比如电商系统中的订单统计(统计所有商品总价、数量、重量)。
4. 元素类之间差异较大,且需要统一处理:比如不同类型的日志(访问日志、错误日志、业务日志),需要统一收集和分析。
绝对不适用场景
1. 对象结构频繁变化:比如初创公司的产品模块,商品类型每周都在新增,使用访问者模式会导致代码爆炸。
2. 操作与元素紧密耦合:比如元素的核心业务逻辑(如商品的库存扣减),不适合抽离为访问者。
3. 简单对象结构:比如只有一两种元素的系统,使用访问者模式会过度设计,增加代码复杂度。
六、总结:访问者模式的设计哲学

访问者模式的本质,是用"牺牲元素扩展性"换取"操作扩展性"。它是一种典型的"以空间换时间"、"以一种耦合换另一种耦合"的设计思想——在对象结构稳定的前提下,通过将操作抽离为访问者,实现操作的快速扩展。
在C++开发中使用访问者模式时,建议记住三个实战技巧:
-
优先用智能指针:管理元素对象的生命周期,避免内存泄漏(如本文示例中的shared_ptr)。
-
合理暴露接口:通过友元类或私有成员访问器,控制访问者对元素属性的访问权限,避免过度暴露。
-
结合其他模式优化:比如用工厂模式创建访问者,用单例模式管理全局访问者,用装饰器模式扩展访问者功能。
最后需要强调的是,设计模式不是银弹,不要为了用模式而用模式。在实际开发中,先写出能跑通的代码,再根据业务演进和代码痛点,逐步引入合适的设计模式——这才是优秀开发者的正确姿势。
如果你在使用访问者模式时遇到了具体问题,或者有更好的优化技巧,欢迎在评论区留言讨论!
635

被折叠的 条评论
为什么被折叠?



