设计模式讲解01-建造者模式(Builder)
1. 概述
建造者模式也称为:生成器模式
定义:建造者模式是一种创建型设计模式,它允许你将创建复杂对象的步骤与表示方式相分离。
解释:建造者模式就是将复杂对象的创建过程拆分成多个简单对象的创建过程,并将这些简单对象组合成复杂对象!
2. 优缺点
优点 | 缺点 |
|
|
|
|
|
3. 结构
建造者模式包含以下几个主要角色:
- 产品(Product):要构建的复杂对象;产品类通常包含多个部分或者属性,并由具体的建造者逐步构建而成。
- 抽象建造者(Builder):定义了构建产品的抽象接口,包括构建产品的各个部分的方法;通常包括多个构建方法和一个返回产品的方法。
- 具体建造者(Concrete Builder):实现了抽象建造者接口,具体确定如何构建产品的各个部分,并负责返回最终构建的产品。
- 指导者(Director):负责调用建造者的方法来构建产品;指导者并不了解具体的构建过程,只关心产品的构建顺序和方式。
4. 代码实现
4.1. 需求介绍
我们假设一个快餐店的商业案例,其中,一个典型的套餐可以是一个汉堡(Burger)和一杯冷饮(Cold drink)。汉堡(Burger)可以是素食汉堡(Veg Burger)或鸡肉汉堡(Chicken Burger),它们是包在纸盒中。冷饮(Cold drink)可以是可口可乐(coke)或百事可乐(pepsi),它们是装在瓶子中。
我们将创建一个表示食物条目(比如汉堡和冷饮)的 Item 接口和实现 Item 接口的实体类,以及一个表示食物包装的 Packing 接口和实现 Packing 接口的实体类,汉堡是包在纸盒中,冷饮是装在瓶子中。
然后我们创建一个 Meal 类,带有 Item 的 ArrayList 和一个通过结合 Item 来创建不同类型的 Meal 对象的 MealBuilder。BuilderPatternDemo 类使用 MealBuilder 来创建一个 Meal。
4.2. 代码演示
- 创建一个代表食物条目和食物包装的接口。
/*** @Description 食品条目接口* @Author gongming.Zhang* @Date 2024/11/1 15:54* @Version 1.0*/
public interface Item {// 商品名称String name();// 包装类型 (纸盒、瓶子)Packing packing();// 价格float price();
}
package top.zhang.builderdesignpatterns.entity.packing;/*** @Description 食物包装条目接口* @Author gongming.Zhang* @Date 2024/11/1 15:56* @Version 1.0*/
public interface Packing {// 包装类型(纸盒、瓶子)String pack();
}
- 创建并实现
Packing
接口的实体类。
/*** @Description 纸盒实现类* @Author gongming.Zhang* @Date 2024/11/1 15:57* @Version 1.0*/
public class Wrapper implements Packing {@Overridepublic String pack() {return "Wrapper";}
}
/*** @Description 瓶子实现类* @Author gongming.Zhang* @Date 2024/11/1 15:58* @Version 1.0*/
public class Bottle implements Packing {@Overridepublic String pack() {return "Bottle";}
}
- 创建并实现
Item
接口的抽象类,该类提供默认的功能。
/*** @Description 汉堡抽象类* @Author gongming.Zhang* @Date 2024/11/1 16:00* @Version 1.0*/
public abstract class Burger implements Item {@Overridepublic Packing packing() {return new Wrapper();}@Overridepublic abstract float price();
}
/*** @Description 冷饮抽象类* @Author gongming.Zhang* @Date 2024/11/1 16:24* @Version 1.0*/
public abstract class ColdDrink implements Item {@Overridepublic Packing packing() {return new Bottle();}@Overridepublic abstract float price();
}
- 创建并继承
Burger
和ColdDrink
。
/*** @Description 鸡肉汉堡实体类* @Author gongming.Zhang* @Date 2024/11/1 16:28* @Version 1.0*/
public class ChickenBurger extends Burger {@Overridepublic String name() {return "Chicken Burger";}@Overridepublic float price() {return 50.5f;}
}
/*** @Description 素食汉堡实体类* @Author gongming.Zhang* @Date 2024/11/1 16:26* @Version 1.0*/
public class VegBurger extends Burger {@Overridepublic String name() {return "Veg Burger";}@Overridepublic float price() {return 25.0f;}
}
/*** @Description 可口可乐实体类* @Author gongming.Zhang* @Date 2024/11/1 16:28* @Version 1.0*/
public class Coke extends ColdDrink {@Overridepublic String name() {return "Coke";}@Overridepublic float price() {return 30.0f;}
}
/*** @Description 百事可乐实体类* @Author gongming.Zhang* @Date 2024/11/1 16:30* @Version 1.0*/
public class Pepsi extends ColdDrink {@Overridepublic String name() {return "Pepsi";}@Overridepublic float price() {return 35.0f;}
}
- 创建一个
Meal
类,表示菜品实体。(产品)
package top.zhang.builderdesignpatterns.entity;import top.zhang.builderdesignpatterns.entity.food.Item;import java.util.ArrayList;
import java.util.List;/*** @Description 菜品实体类 —— 产品* @Author gongming.Zhang* @Date 2024/11/1 16:31* @Version 1.0*/
public class Meal {private List<Item> items = new ArrayList<Item>();public void addItem(Item item) {items.add(item);}/*** 获取购买的商品总价** @return 商品总价格*/public float getCost() {float cost = 0.0f;for (Item item : items) {cost += item.price();}return cost;}/*** 展示购买的商品信息**/public void showItems() {for (Item item : items) {System.out.print("Item : "+item.name());System.out.print(", Packing : "+item.packing().pack());System.out.println(", Price : "+item.price());}}
}
- 创建一个
MealBuilder
类,实际的builder
类负责创建Meal
对象。(具体建造者)
package top.zhang.builderdesignpatterns.entity;import top.zhang.builderdesignpatterns.entity.food.entity.ChickenBurger;
import top.zhang.builderdesignpatterns.entity.food.entity.Coke;
import top.zhang.builderdesignpatterns.entity.food.entity.Pepsi;
import top.zhang.builderdesignpatterns.entity.food.entity.VegBurger;/*** @Description 负责构建 Meal 对象 —— 具体建造者* @Author gongming.Zhang* @Date 2024/11/1 16:34* @Version 1.0*/
public class MealBuilder {/*** 构建蔬菜餐数据** @return 菜品实体类*/public Meal prepareVegMeal() {Meal meal = new Meal();meal.addItem(new VegBurger());meal.addItem(new Coke());return meal;}/*** 构建非蔬菜餐数据** @return 菜品实体类*/public Meal prepareNonVegMeal() {Meal meal = new Meal();meal.addItem(new ChickenBurger());meal.addItem(new Pepsi());return meal;}
}
- 测试建造者模式
@SpringBootTest
@RunWith(SpringRunner.class)
class BuilderDesignPatternsApplicationTests {@Testpublic void BuilderPatternDemo() {MealBuilder mealBuilder = new MealBuilder();Meal vegMeal = mealBuilder.prepareVegMeal();System.out.println("Veg Meal");vegMeal.showItems();System.out.println("total Cost: " + vegMeal.getCost());System.out.println("\n\n");Meal nonVegMeal = mealBuilder.prepareNonVegMeal();System.out.println("Non-Veg Meal");nonVegMeal.showItems();System.out.println("Total Cost: " +nonVegMeal.getCost());}
}
5. 总结
使用场景:
- 当需要创建一些特定的对象,但是它们拥有共同的组成部分时,比如:一个房子可以由个个部件:框架、墙、窗户等,这些部件可以组合起来构造完整的房子。
- 当对象的构建过程比较复杂且需要多个步骤时,例如,创建一份电子商务订单需要多个步骤,如选择商品、填写地址和支付等,这些步骤可以被分别封装成为订单构建器中的不同方法。
- 当需要创建一些特定类型的对象,例如复杂的数据结构或配置对象时,这在编写配置文件解析器以及通用数据结构如二叉树等时很有用。
- 建造者模式也可以被用于通过更高级的方式来构建复杂对象,例如:序列化和反序列化。
与抽象工厂模式的区别:
抽象工厂模式强调的是产品族的创建,即相关的产品一起被创建出来,而建造者模式强调的是一个复杂对象的创建,即它的各个部分逐步被创建出来。
相关文章:

设计模式讲解01-建造者模式(Builder)
1. 概述 建造者模式也称为:生成器模式 定义:建造者模式是一种创建型设计模式,它允许你将创建复杂对象的步骤与表示方式相分离。 解释:建造者模式就是将复杂对象的创建过程拆分成多个简单对象的创建过程,并将这些简单…...

wflow-web:开源啦 ,高仿钉钉、飞书、企业微信的审批流程设计器,轻松打造属于你的工作流设计器
嗨,大家好,我是小华同学,关注我们获得“最新、最全、最优质”开源项目和高效工作学习方法 wflow-web是一个开源的工作流设计器,它支持可视化拖拽表单组件,动态任意层级结构审批节点,以及复杂流程条件的设置…...
Promise 简单介绍及深入挖掘
一、什么是 Promise? 在 JavaScript 中,Promise 是用于处理异步操作的一种方式。它代表了一个 可能 在将来某个时间点完成或失败的操作的结果。Promise 使得我们能够优雅地处理异步代码,避免了回调地狱(Callback Hell)…...

103 - Lecture 1
Introduction to Database 一、Introduction to Database Systems 1. 数据的定义 What is Data? EX: data could be a docx file storing your project status report; data could be a spreadsheet containing information • 数据只有在设计的场景中才有意义。ÿ…...
Ubuntu 20.04禁用或者移除 cloud-init
1、禁用cloud-init 这是最简单最安全的方法,在 /etc/cloud 目录下创建 cloud-init.disabled 文件重启后生效。删除该文件就可以恢复 # 创建cloud-init.disabled文件 sudo touch /etc/cloud/cloud-init.disabled # 重启 reboot 2、移除 cloud-init 软件包及文件夹…...

DevOps开发运维简述
DevOps平台是一套集成的解决方案,旨在协调软件开发(Development)和信息技术运维(Operations)。它促进跨功能团队合作,实现自动化流程,确保持续集成与持续交付(CI/CD)。 一…...
C++之list的使用
在C中,std::list 是一个双向链表,它允许在列表的任何位置高效地插入和删除元素。以下是一些基本的使用方式: 包含头文件 要使用 std::list,首先需要包含头文件 <iostream> 和 /list>。 #include <iostream> #in…...
nginx配置代理地址
1,配置19上的代理 location /jmis/ { alias D:/images/; autoindex on; sendfile on; } 2.在18服务器上访问19的图片。18服务器nginx代理 proxy_set_header 指令用于在发送给后端服务器的请求中添加或修改指定的HTTP头信息。 proxy_p…...

国际版JAVA同城打车源码同城服务线下结账系统源码适配PAD支持Android+IOS+H5
一、数据中心 总用户数今日接单数量今日新增今日收入本月新增本月收入本年新增本年收入 二、用户中心 全部用户普通用户师傅用户推广员用户 三、财务中心 提现管理收入统计提现统计充值统计充值记录保证金管理平台收入统计 四、首页装修 轮播图分享图语音播报配置 五…...

AndroidLab:一个系统化的Android代理框架,包含操作环境和可复现的基准测试,支持大型语言模型和多模态模型。
2024-10-31,由清华大学和北京大学共同创建的AndroidLab数据集,为安卓自主代理的训练和评估提供了一个包含操作环境、行动空间和可复现基准的系统框架,这对于推动安卓代理技术的发展具有重要意义。 数据集地址:Android Instruct|A…...
Java--正则表达式入门指南
正则表达式(Regular Expression)是一种用于匹配字符串中字符模式的工具。在Java中,正则表达式的使用主要依赖于java.util.regex包,其中最重要的两个类是Pattern和Matcher。今天将探讨正则表达式的基础概念、书写规则、常用方法&am…...
阿里云服务器 篇十(加更二):自动定时备份CSDN博客内容:更新文件最后修改时间,以在个人博客正确展示最近更新
文章目录 系列文章核心修改更新后的核心代码使用方法系列文章 阿里云服务器 篇一:申请和初始化 阿里云服务器 篇二:搭建静态网站 阿里云服务器 篇三:提交搜索引擎收录 阿里云服务器 篇四:404页面模板 阿里云服务器 篇五:短链服务网站 阿里云服务器 篇六:GitHub镜像网站 …...
Python编程探索:从基础语法到循环结构实践
文章目录 前言1. 行与缩进:Python代码的灵魂2. 数据类型的转换:灵活处理数据3. 字符串切片:提取字符串的子部分4. 字符串拼接:连接多个字符串5. 逻辑运算符:处理布尔值6. 成员运算符:检查值是否存在于序列中…...

今天要重新认识下注解@RequestBody
在Spring框架中,RequestBody是一个常用的注解,它用于将HTTP请求体中的数据绑定到控制器(Controller)处理方法的参数上。这个注解通常与RESTful Web服务一起使用,在处理POST或PUT请求时尤为常见,因为这些请求…...

北斗有源终端|智能5G单北斗终端|单兵|单北斗|手持机
在当今科技日新月异的时代,智能设备的创新与升级速度令人目不暇接。其中,智能5G终端作为连接数字世界的桥梁,正逐步渗透到我们生活的方方面面。今天,让我们聚焦于一款集尖端科技与实用功能于一身的智能5G设备——QM-L5智能5G单北斗…...

【题解】—— LeetCode一周小结44
🌟欢迎来到 我的博客 —— 探索技术的无限可能! 🌟博客的简介(文章目录) 【题解】—— 每日一道题目栏 上接:【题解】—— LeetCode一周小结43 28.冗余连接 II 题目链接:685. 冗余连接 II 在…...
faiss 用于检索10亿向量(维度768)的方法
faiss 用检索10亿向量(维度768)的方法,注意考虑占用内存空间大小不能超过100G,因为100G已经是很多服务器内存的极限了,有的128G已经是超规格的机器了。价格也就是2000左右(月租)。 要处理 10 亿个 768 维的向量,并且限制内存占用不超过 100G,我们需要使用 FAISS 中的…...

sql专题 之 常用命令
文章目录 查询基础语法查询全表查询选择查询:常量和运算: 条件查询where运算符:、 !、<、>空值:null模糊查询:like逻辑运算:and or not 去重:distinct排序:order by截断和偏移…...

Kubernetes Extended Resource 扩展资源使用简介
Kubernetes 除了提供基于 CPU 和内存的传统计算资源调度外,还支持自定义的 Extended Resource 扩展资源,以便调度和管理其它各种类型的资源。 Extended Resource Extended Resource 扩展资源的创建和使用过程如下图所示: 定义资源ÿ…...

基于STM32的天气时钟项目教学
引言 随着物联网技术的普及,基于STM32的微控制器被广泛应用于各种智能设备的开发。本项目旨在打造一个基于STM32的天气时钟,除了显示当前时间,还可以通过Wi-Fi获取当地天气信息,提供一个实用的生活工具。 环境准备 在开始项目之前…...
进程地址空间(比特课总结)
一、进程地址空间 1. 环境变量 1 )⽤户级环境变量与系统级环境变量 全局属性:环境变量具有全局属性,会被⼦进程继承。例如当bash启动⼦进程时,环 境变量会⾃动传递给⼦进程。 本地变量限制:本地变量只在当前进程(ba…...

shell脚本--常见案例
1、自动备份文件或目录 2、批量重命名文件 3、查找并删除指定名称的文件: 4、批量删除文件 5、查找并替换文件内容 6、批量创建文件 7、创建文件夹并移动文件 8、在文件夹中查找文件...

python/java环境配置
环境变量放一起 python: 1.首先下载Python Python下载地址:Download Python | Python.org downloads ---windows -- 64 2.安装Python 下面两个,然后自定义,全选 可以把前4个选上 3.环境配置 1)搜高级系统设置 2…...
使用van-uploader 的UI组件,结合vue2如何实现图片上传组件的封装
以下是基于 vant-ui(适配 Vue2 版本 )实现截图中照片上传预览、删除功能,并封装成可复用组件的完整代码,包含样式和逻辑实现,可直接在 Vue2 项目中使用: 1. 封装的图片上传组件 ImageUploader.vue <te…...

Java-41 深入浅出 Spring - 声明式事务的支持 事务配置 XML模式 XML+注解模式
点一下关注吧!!!非常感谢!!持续更新!!! 🚀 AI篇持续更新中!(长期更新) 目前2025年06月05日更新到: AI炼丹日志-28 - Aud…...

Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决
Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决 问题背景 在一个基于 Spring Cloud Gateway WebFlux 构建的微服务项目中,新增了一个本地验证码接口 /code,使用函数式路由(RouterFunction)和 Hutool 的 Circle…...
AGain DB和倍数增益的关系
我在设置一款索尼CMOS芯片时,Again增益0db变化为6DB,画面的变化只有2倍DN的增益,比如10变为20。 这与dB和线性增益的关系以及传感器处理流程有关。以下是具体原因分析: 1. dB与线性增益的换算关系 6dB对应的理论线性增益应为&…...
Webpack性能优化:构建速度与体积优化策略
一、构建速度优化 1、升级Webpack和Node.js 优化效果:Webpack 4比Webpack 3构建时间降低60%-98%。原因: V8引擎优化(for of替代forEach、Map/Set替代Object)。默认使用更快的md4哈希算法。AST直接从Loa…...
【学习笔记】erase 删除顺序迭代器后迭代器失效的解决方案
目录 使用 erase 返回值继续迭代使用索引进行遍历 我们知道类似 vector 的顺序迭代器被删除后,迭代器会失效,因为顺序迭代器在内存中是连续存储的,元素删除后,后续元素会前移。 但一些场景中,我们又需要在执行删除操作…...
在 Spring Boot 项目里,MYSQL中json类型字段使用
前言: 因为程序特殊需求导致,需要mysql数据库存储json类型数据,因此记录一下使用流程 1.java实体中新增字段 private List<User> users 2.增加mybatis-plus注解 TableField(typeHandler FastjsonTypeHandler.class) private Lis…...