如何用智能指针实现C++建造者设计模式?
用智能指针实现C++建造者模式的现代版本
智能指针选择核心逻辑
std::unique_ptr:优先用于独占所有权的场景,比如建造者创建的产品——默认情况下,产品的所有权应该由建造者转移给调用方,不需要多组件共享,unique_ptr的移动语义刚好适配这种所有权转移需求。std::shared_ptr:仅当你需要多个组件长期持有同一个产品实例时才使用,比如多个业务模块需要同时访问产品且生命周期不一致,否则没必要用(会带来额外的引用计数开销)。- 传递规则:
- 转移所有权:用
std::unique_ptr<T>&&(右值引用)或直接返回unique_ptr<T>,调用时用std::move()转移。 - 临时访问:如果只是需要读取产品/建造者的状态,用
const T&或者非拥有的裸指针(T*)即可,不需要传递智能指针。
- 转移所有权:用
改造后的完整代码
基于你参考的建造者模式示例,以下是适配智能指针的现代C++实现:
#include <iostream> #include <memory> #include <vector> #include <string> // 产品类:和原示例逻辑一致,只是不再通过裸指针返回 class Product { public: std::vector<std::string> parts_; void ListParts() const { std::cout << "Product parts: "; for (size_t i = 0; i < parts_.size(); ++i) { if (parts_[i] == parts_.back()) { std::cout << parts_[i]; } else { std::cout << parts_[i] << ", "; } } std::cout << "\n\n"; } }; // 抽象建造者:修改GetResult返回unique_ptr class Builder { public: virtual ~Builder() = default; virtual void ProducePartA() = 0; virtual void ProducePartB() = 0; virtual void ProducePartC() = 0; virtual std::unique_ptr<Product> GetResult() = 0; }; // 具体建造者:用unique_ptr管理产品实例 class ConcreteBuilder1 : public Builder { private: std::unique_ptr<Product> product_ = std::make_unique<Product>(); public: // 重置产品实例,准备创建新对象 void Reset() { product_ = std::make_unique<Product>(); } void ProducePartA() override { product_->parts_.push_back("PartA1"); } void ProducePartB() override { product_->parts_.push_back("PartB1"); } void ProducePartC() override { product_->parts_.push_back("PartC1"); } // 转移产品所有权给调用方,调用后建造者不再持有该产品 std::unique_ptr<Product> GetResult() override { return std::move(product_); } }; // 指挥者:不需要持有任何智能指针,只需要引用建造者即可 class Director { private: Builder* builder_ = nullptr; public: void set_builder(Builder* builder) { builder_ = builder; } // 构建不同配置的产品 void BuildMinimalViableProduct() { builder_->ProducePartA(); } void BuildFullFeaturedProduct() { builder_->ProducePartA(); builder_->ProducePartB(); builder_->ProducePartC(); } }; // 客户端代码 int main() { Director director; ConcreteBuilder1 builder; director.set_builder(&builder); std::cout << "Standard basic product:\n"; director.BuildMinimalViableProduct(); auto product1 = builder.GetResult(); product1->ListParts(); // 重置建造者,创建新产品 builder.Reset(); std::cout << "Standard full featured product:\n"; director.BuildFullFeaturedProduct(); auto product2 = builder.GetResult(); product2->ListParts(); // 不需要手动delete,智能指针自动管理生命周期 return 0; }
关键改造点说明
- 产品所有权转移:
ConcreteBuilder1的GetResult()通过std::move()转移unique_ptr的所有权,调用方拿到产品后完全拥有它,建造者不再持有,避免了裸指针的内存泄漏风险。 - 建造者的生命周期:客户端直接创建具体建造者的栈实例,不需要用智能指针——因为客户端是建造者的所有者,指挥者只是临时使用它,不需要持有所有权。如果需要动态创建建造者(比如基于配置选择不同建造者),可以用
std::unique_ptr<Builder>来管理。 - 何时用shared_ptr?:如果你的业务场景中,比如多个
Director或者其他组件需要同时持有同一个Product实例,且生命周期不一致,那可以把unique_ptr换成shared_ptr,GetResult()返回shared_ptr<Product>,此时建造者和调用方共享所有权。
内容的提问来源于stack exchange,提问作者WolfyDoo
相关产品推荐
相关产品推荐

