C++设计模式:建造者模式(详解+案例代码)
建造者模式
建造者模式是一种对象创建型模式之一,用来隐藏复合对象的创建过程,它把复合对象的创建过程加以抽象,通过子类继承和重载的方式,动态地创建具有复合属性的对象。官方说法就是将一个复杂对象的构造与它的表示分离,使同样的构建过程可以创建不同的表示。
主要解决在软件系统中,有时候面临着"一个复杂对象"的创建工作,其通常由各个部分的子对象用一定的算法构成;由于需求的变化,这个复杂对象的各个部分经常面临着剧烈的变化,但是将它们组合在一起的算法却相对稳定。
实现步骤
- 提供抽象建造者类: 为创建产品各个部分,统一抽象接口
- 提供具体建造者类:具体实现抽象建造者各个部件的接口
- (可选)提供抽象产品类:为产品提供统一接口
- 提供多个具体产品类:实现抽象产品类的接口。
- (重要)提供一个指挥类:负责安排和调度复杂对象的各个建造过程
实现代码
案例一: 组装电脑
- 抽象产品类:AbstractProduct,把电脑的各个组成部件抽象为一个统一的接口
- 具体产品类:Computer,电脑产品
- 抽象建造类:AbstractBuilder:创建电脑的各个部分,提供统一接口
- 具体建造类:ComputerBuilder:电脑建造者,负责实现抽象建造者的接口。
- 指挥类:Director: 相当于一个指挥者,指挥电脑建造者构造电脑。
/* 建造者模式 组装电脑:显示器 主机 键盘 鼠标 */ /* 1. 抽象产品类 */ class AbstractProduct { public: virtual ~AbstractProduct() {} virtual void setDisplay(string display) = 0; virtual void setHost(string host) = 0; virtual void setKeyBoard(string KeyBoard) = 0; virtual void setMouse(string mouse) = 0; virtual void show() = 0; }; /* 2. 具体产品类 */ class Computer:public AbstractProduct { public: ~Computer() {} void setDisplay(string display) { m_vec.emplace_back(display); } void setHost(string host) { m_vec.emplace_back(host); } void setKeyBoard(string KeyBoard) { m_vec.emplace_back(KeyBoard); } void setMouse(string mouse) { m_vec.emplace_back(mouse); } void show() { cout << "----------组装电脑---------" << endl; for (auto& x : m_vec) { cout << x << endl; } } private: vector<string> m_vec; }; /* 3. 抽象建造者 */ class AbstractBuilder { public: //创建电脑产品 AbstractBuilder() :product(new Computer) {} virtual ~AbstractBuilder() {} //抽象电脑产品创建的统一抽象接口 virtual void BuildDisplay(string display) = 0; virtual void BuildHost(string host) = 0; virtual void BuildKeyBoard(string KeyBoard) = 0; virtual void BuildMouse(string mouse) = 0; AbstractProduct* getProduct() { return product; } protected: AbstractProduct* product; }; /* 4. 具体建造者:具体实现抽象建造者各个部件的接口 */ class ComputerBuilder :public AbstractBuilder { public: ~ComputerBuilder() {} void BuildDisplay(string display) { product->setDisplay(display); } void BuildHost(string host) { product->setHost(host); } void BuildKeyBoard(string KeyBoard) { product->setKeyBoard(KeyBoard); } void BuildMouse(string mouse) { product->setMouse(mouse); } }; /* 5. 指挥者:安排和调度复杂对象的创建过程 */ class Director { public: Director(AbstractBuilder* builder) :m_builder(builder) {} ~Director() {} AbstractProduct* createComputer(string display, string host, string KeyBoard, string mouse) { m_builder->BuildDisplay(display); m_builder->BuildHost(host); m_builder->BuildKeyBoard(KeyBoard); m_builder->BuildMouse(mouse); return m_builder->getProduct(); } private: AbstractBuilder* m_builder; }; int main() { //1. 创建电脑建造者 AbstractBuilder* Computer_Builder = new ComputerBuilder; //2. 创建电脑建造者的 管理者 Director* pDcomp = new Director{ Computer_Builder }; //3. 管理者指挥 建造者制造电脑产品 AbstractProduct* computerPro = pDcomp->createComputer("联想显示器", "外星人主机", "雷蛇键盘", "罗技鼠标"); //4. 电脑产品制造完成 computerPro->show(); //别忘了释放内存 delete Computer_Builder; delete pDcomp; delete computerPro; return 0; }
案例二:汉堡店点餐
- 抽象产品类: AbstractFood
- 具体产品类:Food
- 抽象建造者:AbstractBuilder
- (套餐A)具体建造者A:Meal_1
- (套餐B)具体建造者B:Meal_2
- 指挥者:Director :负责上菜
/* 点餐: 1. 香辣鸡肉汉堡 + 薯条 + 可乐 2. 墨西哥鸡肉卷 + 鸡块 + 芬达 */ //1. 抽象产品类 class AbstractFood { public: virtual ~AbstractFood() {} virtual void add(string foodname, int price) = 0; virtual void show() = 0; }; //2. 具体产品类 class Food:public AbstractFood { public: virtual ~Food() {} void add(string foodname, int price) { m_vec.emplace_back(make_pair(foodname, price)); } void show() { int sum = 0; for (int i = 0; i < m_vec.size(); i++) { sum += m_vec[i].second; cout << m_vec[i].first <<": "<< m_vec[i].second<<"元" << endl; } cout << "总计: " << sum << "元" << endl; } private: vector<pair<string,int>> m_vec; }; //3. 抽象建造者 class AbstractBuilder { public: AbstractBuilder() :food(new Food) {} virtual ~AbstractBuilder() {} virtual void BuildFood1() = 0; virtual void BuildFood2() = 0; virtual void BuildFood3() = 0; AbstractFood* getFood() { return food; } protected: AbstractFood* food; }; //4.1 具体建造者A class Meal_1 :public AbstractBuilder { public: ~Meal_1() {} void BuildFood1() { food->add("香辣鸡腿堡", 10); } void BuildFood2() { food->add("薯条", 5); } void BuildFood3() { food->add("可乐", 3); } }; //4.2 具体建造者B class Meal_2 :public AbstractBuilder { public: ~Meal_2() {} void BuildFood1() { food->add("墨西哥鸡肉卷", 10); } void BuildFood2() { food->add("鸡块", 5); } void BuildFood3() { food->add("芬达", 3); } }; //5. 指挥者: 最后上菜 class Director { public: ~Director() {} Director(AbstractBuilder* foodBuilder) :fooder(foodBuilder) {} AbstractFood* createFood() { fooder->BuildFood1(); fooder->BuildFood2(); fooder->BuildFood3(); return fooder->getFood(); } private: AbstractBuilder* fooder; }; void menu() { cout << "-----------欢迎光临汉堡店:-----------" << endl; cout << "-------1. 香辣鸡肉汉堡 + 薯条 + 可乐" << endl; cout << "-------2. 墨西哥鸡肉卷 + 鸡块 + 芬达" << endl; cout << "------------------------------------" << endl; } int main() { unique_ptr<AbstractBuilder> fooder1(new Meal_1); unique_ptr<Director> pD1(new Director(fooder1.get())); unique_ptr<AbstractFood> food1((pD1.get()->createFood())); unique_ptr<AbstractBuilder> fooder2(new Meal_2); unique_ptr<Director> pD2(new Director{ fooder2.get()}); unique_ptr<AbstractFood> food2(pD2.get()->createFood()); int choice{}; menu(); cout << "您的选择:"; cin >> choice; switch (choice) { case 1: food1->show(); break; case 2: food2->show(); break; } return 0; }
运行如下:
tips: C++实现建造者模式容易出现内存泄露的隐患,例如汉堡店的这个例子:
我们建议使用智能指针,否则会造成隐晦的delete操作不明确的事实。
//1. 做套餐A的厨师 AbstractBuilder* Fooder1 = new Meal_1; //2. 指挥者指挥厨师可以做了 Director* pD1 = new Director{ Fooder1 }; //3. 套餐A做好了 AbstractFood* food1 = Fooder1->getFood(); //4. 上菜 food1->show(); AbstractBuilder* Fooder2 = new Meal_2; Director* pD2 = new Director{ Fooder2 }; AbstractFood* food2 = Fooder2->getFood(); .... // 6 个delete一个都不能少!!!! delete Fooder1; delete pD1 ; delete food1 ; delete Fooder2; delete pD2; delete food2 ;
优缺点
优点
-
封装性好,构建和表示分离
-
扩展性好,各个具体的建造者相互独立,有利于系统的解耦
-
控制细节风险,客户端无需详知细节,建造者细化创建过程
缺点
-
产品的组成部分必须相同,这限制了其使用范围
-
产品内部发生变化,建造者需同步修改,后期维护成本较大
本文来自博客园,作者:hugeYlh,转载请注明原文链接:https://www.cnblogs.com/helloylh/p/17209629.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)