C++设计模式:建造者模式(详解+案例代码)

news2024/11/24 6:02:16

文章目录

  • 建造者模式
    • 实现步骤
    • 实现代码
      • 案例一: 组装电脑
      • 案例二:汉堡店点餐
    • 优缺点

建造者模式

建造者模式是一种对象创建型模式之一,用来隐藏复合对象的创建过程,它把复合对象的创建过程加以抽象,通过子类继承和重载的方式,动态地创建具有复合属性的对象。官方说法就是将一个复杂对象的构造与它的表示分离,使同样的构建过程可以创建不同的表示。

主要解决在软件系统中,有时候面临着"一个复杂对象"的创建工作,其通常由各个部分的子对象用一定的算法构成;由于需求的变化,这个复杂对象的各个部分经常面临着剧烈的变化,但是将它们组合在一起的算法却相对稳定。

实现步骤

  1. 提供抽象建造者类: 为创建产品各个部分,统一抽象接口
  2. 提供具体建造者类:具体实现抽象建造者各个部件的接口
  3. (可选)提供抽象产品类:为产品提供统一接口
  4. 提供多个具体产品类:实现抽象产品类的接口。
  5. (重要)提供一个指挥类:负责安排和调度复杂对象的各个建造过程

请添加图片描述

实现代码

案例一: 组装电脑

  1. 抽象产品类:AbstractProduct,把电脑的各个组成部件抽象为一个统一的接口
  2. 具体产品类:Computer,电脑产品
  3. 抽象建造类:AbstractBuilder:创建电脑的各个部分,提供统一接口
  4. 具体建造类:ComputerBuilder:电脑建造者,负责实现抽象建造者的接口。
  5. 指挥类: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;
}

在这里插入图片描述


案例二:汉堡店点餐

  1. 抽象产品类: AbstractFood
  2. 具体产品类:Food
  3. 抽象建造者:AbstractBuilder
  4. (套餐A)具体建造者A:Meal_1
  5. (套餐B)具体建造者B:Meal_2
  6. 指挥者: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 ;

优缺点

优点

  • 封装性好,构建和表示分离

  • 扩展性好,各个具体的建造者相互独立,有利于系统的解耦

  • 控制细节风险,客户端无需详知细节,建造者细化创建过程

缺点

  • 产品的组成部分必须相同,这限制了其使用范围

  • 产品内部发生变化,建造者需同步修改,后期维护成本较大

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/144359.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【JavaEE】设计模式之单例模式

✨哈喽&#xff0c;进来的小伙伴们&#xff0c;你们好耶&#xff01;✨ &#x1f6f0;️&#x1f6f0;️系列专栏:【JavaEE】 ✈️✈️本篇内容:设计模式之单例模式。 &#x1f680;&#x1f680;代码存放仓库gitee&#xff1a;JavaEE初阶代码存放&#xff01; ⛵⛵作者简介&am…

Redis 连接池报错:jwtCalibrateHandler 48 max number of clients reached

问题[ERROR 2023-01-06 15:37:58,877] jwtCalibrateHandler 48 max number of clients reached早上突然看到反馈说redis连接异常&#xff0c;就是这个&#xff1a;max number of clients reached。问题很显然就是redis连接数超了.原因分析redis maxclients 是redis server的重要…

VMware vCenter Server Appliance空间不足问题处理

原创作者&#xff1a;运维工程师 谢晋 前提提要 客户环境为VSAN环境&#xff0c;VCSA版本为6.7&#xff0c;偶然间发现VSAN监控的性能不能正常打开&#xff0c;如下图&#xff1a;     后登陆https://VCSAIP:5480发现出现告警&#xff0c;报错log日志满了 故障处理 开…

rabbitmq+netcore6 【3】Publish/Subscribe:发布/订阅

文章目录1&#xff09;前言2&#xff09;临时队列3&#xff09;绑定4&#xff09;综合以上代码准备工作1、生产者2、消费者13、消费者25&#xff09;验证官网教程原文链接&#xff1a; https://www.rabbitmq.com/tutorials/tutorial-three-dotnet.html翻译版参考链接&#xff1…

大话测试数据(二):概念测试数据的获取

在大话测试数据&#xff08;一&#xff09;文章中&#xff0c;我提到&#xff0c;获取数据的第一步是获取概念上数据。这一步看起来简单&#xff0c;其实不是那么容易。获取概念数据和获取需求的过程是交织在一起的&#xff0c;事实上&#xff0c;它们其实是一个事儿&#xff0…

Ribbon、Feign、Hystrix超时重试熔断问题

文章目录问题描述重试次数不生效开启熔断后重试次数生效fallbackFactory回退降级异常为空问题1分析问题2、3分析总结feign请求次数计算Hystrix超时时间设置公式问题描述 在使用Ribbon、Feign、Hystrix组合时&#xff0c;因为配置的问题出现以下现象&#xff0c;让我的大脑CPU烧…

[SWPU2019]Web1

目录 [SWPU2019]Web1 无列名查看表数据 不使用列名查询表中数据 [SWPU2019]Web1 首先我们先注册&#xff0c;登录进来后看到如下界面&#xff1a; 我们点击申请发布广告&#xff0c;并发送&#xff1a; 查看广告详情&#xff0c;发现疑似存在注入点&#xff1a; 于是我们在发…

Docker 应用篇 | Docker 学习笔记总结

Docker 视频内容可以参考黑马程序员的Docker篇 详细完整内容可以查询菜鸟教程&#xff1a;Docker 教程 本篇博文主要让读者对Docker有一个基本理解并可以借助Docker发布自己的项目 一、初识Docker 1.1 Docker概述 Docker是一个集装箱式的思想 Docker可以让开发者打包他们的…

招聘求职系统|基于Springboot+Vue+Nodejs实现求职招聘系统

作者主页&#xff1a;编程指南针 作者简介&#xff1a;Java领域优质创作者、CSDN博客专家 、掘金特邀作者、多年架构师设计经验、腾讯课堂常驻讲师 主要内容&#xff1a;Java项目、毕业设计、简历模板、学习资料、面试题库、技术互助 收藏点赞不迷路 关注作者有好处 文末获取源…

电脑系统更新后桌面的文件全部不见了怎么恢复?

电脑系统更新是很常见的一种情况&#xff0c;自动更新电脑系统后我们可以进行更优质的使用体验&#xff0c;但是最近有位小伙伴&#xff0c;出现了win10电脑系统更新后桌面文件丢失情况&#xff0c;那么电脑系统更新桌面文件没了怎么办&#xff1f;电脑系统更新桌面文件不见了怎…

实验二十三 基于时间的ACL配置及策略

实验二十三 基于时间的ACL配置及策略实验要求&#xff1a; 某公司通过router实现各部门之间的互连。公司要求禁止销售部门在上班时间(8:00 至18:00)访问工资查询服务器(IP地址为192.168.10.10)&#xff0c;财务部门不受限制&#xff0c;可以 随时访问。网络拓扑图&#xff1a;实…

如何定义算法?10分钟带你弄懂算法的基本概念

算法是指完成一个任务所需要的具体步骤和方法。也就是说给定初始状态或输入数据&#xff0c;经过计算机程序的有限次运算&#xff0c;能够得出所要求或期望的终止状态或输出数据。 编程界的“Pascal之父”Nicklaus Wirth有一句人尽皆知的名言&#xff1a;“算法数据结构程序”…

【目标检测】G-GhostNet

1、论文 论文题目&#xff1a;《GhostNets on Heterogeneous Devices via Cheap Operations》 论文地址&#xff1a; https://arxiv.org/pdf/2201.03297.pdf 代码地址&#xff1a; https://github.com/huawei-noah/CV-Backbones 2、引言 本文针对网络部署时面临的内存和资源…

python提取excel文本框内容

就提取excel文本框的内容&#xff0c;提供两种方法 一、 转成pdf&#xff0c;识别pdf文字 该方法需要注意两点&#xff1a; 1.似乎只能识别选中的文字&#xff08;图片不行&#xff09; 2.会受到精度影响&#xff08;即有可能识别出错字&#xff09; 以下是代码 先转存为pdf格…

IB中文解析,助力冲7分

我们知道&#xff0c;IB、AP、A Level三大国际课程体系都有中文&#xff0c;尤其IB学生&#xff0c;由于必选一门母语与语言&#xff0c;中文成了必选项。IB中文可以说是很多IB学子的心头大患了&#xff0c;引发焦虑的文章比比皆是。 不少家长看到这可能会问&#xff0c;中国学…

【Linux 进程地址空间】

1.程序地址空间的概率&#xff08;C/C的说法不够准确&#xff09;写一段代码来来证明C/C程序地址空间是按上图分布的&#xff1a;#include<stdio.h> #include<string.h> #include<stdlib.h> int uninit; int init100; int main() {printf("code addr:%p…

Anaconda中安装CUDA版本的PyTorch

Question: GPU是一种擅长处理专业计算的处理器。这与中央处理器&#xff08;CPU&#xff09;形成鲜明对比&#xff0c;中央处理器是一种擅长处理一般计算的处理器。CPU是为我们电子设备上大多数典型计算提供动力的处理器。GPU的计算速度比CPU快得多。但是&#xff0c;情况并非…

经验证短视频账号每天最多发3个视频,超过的不予推荐

经验证短视频账号每天最多发3个视频&#xff0c;超过的不予推荐 前两天我在刷短视频的时候&#xff0c;看到一个博主推荐一天可以发几十个视频&#xff0c;感觉有点不对&#xff0c;决定还是自己试一下。 于是&#xff0c;在死亡边缘疯狂试探了好几天&#xff0c;终于得到想要…

在ESXi系统上安装pve

pve是基于debian的&#xff0c;在ESXi上选择系统时建议选择debian并开启虚拟化一、下载下载&#xff1a;https://www.proxmox.com/en/downloads点进下载网站后选择 Proxmox Virtual Environment-->ISO Images-->Proxmox VE 7.3 ISO Installer 下的download按钮二、安装系…

React组件

React组件1.组件基本介绍2.React创建组件的两种方式2.1 函数组件2.2 类与继承2.2.1 class 基本语法2.2.2 extends 实现继承1.组件基本介绍 组件是React中最基本的内容&#xff0c;使用React就是在使用组件组件表示页面中的部分功能多个组件可以实现完整的页面功能组件特点&…