三、建造者模式
文章目录
- 1 基本介绍
- 2 案例
- 2.1 Car 类
- 2.2 CarBuilder 抽象类
- 2.3 EconomyCarBuilder 类
- 2.4 LuxuryCarBuilder 类
- 2.5 CarDirector 类
- 2.6 测试程序
- 2.7 测试结果
- 2.8 总结
- 3 各角色之间的关系
- 3.1 角色
- 3.1.1 Product ( 产品 )
- 3.1.2 Builder ( 抽象建造者 )
- 3.1.3 ConcreteBuilder ( 具体建造者 )
- 3.1.4 Director ( 指挥者 )
- 3.2 类图
- 4 注意事项
- 5 在源码中的使用
- 5.1 RequestConfig.Builder 的源码
- 5.2 使用 RequestConfig.Builder 构建对象
- 5.3 总结
- 6 优点
- 7 使用场景
- 8 总结
1 基本介绍
建造者模式(Builder Pattern)是一种 创建型 设计模式,该模式指出:将一个复杂对象的 构造 与它的 表现 (对象的 类型 及 属性) 分离,使同样的构建过程可以创建不同表现的对象。它允许用户只通过指定复杂对象的 类型 和 内容 来构建它们,而不需要知道内部的具体构建细节。
2 案例
本案例演示了两种类型(经济型和豪华型)的汽车生产(只涉及了组装发动机、轮胎、方向盘):
2.1 Car 类
public class Car { // 汽车类,假设内部很复杂private String engine; // 发动机private String wheel; // 轮胎private String steeringWheel; // 方向盘public String getEngine() {return engine;}public void setEngine(String engine) {this.engine = engine;}public String getWheel() {return wheel;}public void setWheel(String wheel) {this.wheel = wheel;}public String getSteeringWheel() {return steeringWheel;}public void setSteeringWheel(String steeringWheel) {this.steeringWheel = steeringWheel;}@Overridepublic String toString() {return "Car{" +"engine='" + engine + '\'' +", wheel='" + wheel + '\'' +", steeringWheel='" + steeringWheel + '\'' +'}';}
}
2.2 CarBuilder 抽象类
public abstract class CarBuilder { // 抽象的汽车建造者,也可以定义成接口 interface// 以下三个方法的返回值都是 CarBuilder,从而可以使用 链式编程public abstract CarBuilder assembleEngine(); // 组装发动机public abstract CarBuilder assembleWheel(String wheel); // 组装车轮public abstract CarBuilder assembleSteeringWheel(); // 组装方向盘public abstract Car build(); // 返回构建的对象
}
2.3 EconomyCarBuilder 类
public class EconomyCarBuilder extends CarBuilder { // 经济型汽车建造者private Car car;public EconomyCarBuilder() {this.car = new Car();}@Overridepublic CarBuilder assembleEngine() {car.setEngine("小排量发动机");return this;}@Overridepublic CarBuilder assembleWheel(String wheel) {car.setWheel(wheel);return this;}@Overridepublic CarBuilder assembleSteeringWheel() {car.setSteeringWheel("常规方向盘");return this;}@Overridepublic Car build() {return car;}
}
2.4 LuxuryCarBuilder 类
public class LuxuryCarBuilder extends CarBuilder { // 豪华型汽车建造者private Car car;public LuxuryCarBuilder() {this.car = new Car();}@Overridepublic CarBuilder assembleEngine() {car.setEngine("大排量发动机");return this;}@Overridepublic CarBuilder assembleWheel(String wheel) {car.setWheel(wheel);return this;}@Overridepublic CarBuilder assembleSteeringWheel() {car.setSteeringWheel("带加热功能的方向盘");return this;}@Overridepublic Car build() {return car;}
}
2.5 CarDirector 类
public class CarDirector { // 建造汽车的指挥者private CarBuilder carBuilder;public CarDirector(CarBuilder carBuilder) {this.carBuilder = carBuilder;}public Car construct(String wheel) { // 构建一个汽车对象return carBuilder.assembleEngine().assembleWheel(wheel).assembleSteeringWheel().build(); // 使用了 链式编程}
}
2.6 测试程序
public class Main { // 测试程序public static void main(String[] args) {CarDirector carDirector = new CarDirector(new EconomyCarBuilder());Car economyCar = carDirector.construct("耐用的轮胎");System.out.println(economyCar);carDirector = new CarDirector(new LuxuryCarBuilder());Car luxuryCar = carDirector.construct("噪音小的轮胎");System.out.println(luxuryCar);}
}
2.7 测试结果
Car{engine='小排量发动机', wheel='耐用的轮胎', steeringWheel='常规方向盘'}
Car{engine='大排量发动机', wheel='噪音小的轮胎', steeringWheel='带加热功能的方向盘'}
2.8 总结
可以发现,在 CarDirector 构建对象时,既不需要了解是哪个 CarBuilder 的子类在参与构建,也不需要了解 其方法的具体实现,只是简单地传递参数、调用方法即可构建 Car 这个“复杂”(假设它很复杂)的对象。
此外,如果想要构建一种新的(属性不同) Car,只需要继承 CarBuilder 抽象类,并实现其中的方法,就可以将其作为构造 CarDirector 的参数,从而使用 CarDirector 建造 Car 了。
3 各角色之间的关系
3.1 角色
3.1.1 Product ( 产品 )
该角色是一个 复杂 的对象,由 多个部件 组成,具有 一定的功能和特点,不能 直接 通过构造器得到。本案例中,Car 类扮演这个角色。
3.1.2 Builder ( 抽象建造者 )
该角色负责 定义 创建产品对象的各个部件的 方法,并且 定义 返回构建的产品对象的 方法。本案例中,CarBuilder 抽象类扮演这个角色。
3.1.3 ConcreteBuilder ( 具体建造者 )
该角色负责 实现 创建产品对象的各个部件的 方法,并且 实现 返回构建的产品对象的 方法。本案例中,EconomyCarBuilder, LuxuryCarBuilder 类扮演这个角色。
3.1.4 Director ( 指挥者 )
该角色负责 按照一定的顺序 使用 创建产品对象的各个部件的 方法。它并不依赖具体的建造者,只调用在抽象建造者中定义的方法。本案例中,CarDirector 类扮演这个角色。
3.2 类图

说明:这是 传统的 建造者模式的类图,如果希望支持 链式编程,则可以把建造者的所有 buildPart() 方法的返回值从 void 改为 Builder。另外,这些 buildPart() 方法不一定没有参数,根据实际情况而定。
4 注意事项
- 抽象建造者 的设计应包含产品 所有 部件的创建和装配方法,确保每个具体建造者都实现这些方法(使用
abstract关键字修饰)。 - 具体建造者 的编写应根据产品的 组成部分 和 组装顺序 来实现抽象建造者接口。
- 指挥者 需要根据 一定的逻辑和顺序 来调用具体建造者的方法,以组织产品的创建过程。
5 在源码中的使用
5.1 RequestConfig.Builder 的源码
public static class Builder { // Builder 是 RequestConfig 的静态内部类private boolean expectContinueEnabled;private HttpHost proxy;private InetAddress localAddress;// ... 省略很多成员变量Builder() {super();// ... 省略很多赋值}public Builder setExpectContinueEnabled(final boolean expectContinueEnabled) {this.expectContinueEnabled = expectContinueEnabled;return this;}public Builder setProxy(final HttpHost proxy) {this.proxy = proxy;return this;}public Builder setLocalAddress(final InetAddress localAddress) {this.localAddress = localAddress;return this;}// ... 省略了很多方法public RequestConfig build() {return new RequestConfig(expectContinueEnabled,proxy,localAddress,// ... 省略了很多参数normalizeUri);}
}
5.2 使用 RequestConfig.Builder 构建对象
先确保你的项目中已经包含了 Apache HttpClient 的依赖,这里给出 Maven 的依赖:
<dependency><groupId>org.apache.httpcomponents</groupId><artifactId>httpclient</artifactId><version>4.5.13</version>
</dependency>
以下是使用 RequestConfig.Builder 生成 RequestConfig 对象的一个示例:
RequestConfig.Builder builder = RequestConfig.custom().setSocketTimeout(3000).setConnectTimeout(3000).setConnectionRequestTimeout(3000);
RequestConfig config = builder.build();
5.3 总结
Apache HttpClient 中的 RequestConfig.Builder 是一个典型的建造者类示例,它用于构建 RequestConfig 对象,该对象包含了请求的配置信息。
6 优点
- 分离构建和表现:建造者模式将一个复杂对象的构建过程与其表现分离,从而可以更灵活地构建不同表现的对象。
- 易于扩展:由于 具体建造者 和 指导者 之间的 松耦合 关系,可以在不影响客户端代码(即不需要修改 使用
Director建造对象的代码)的前提下,新增 或 替换 具体建造者,从而 扩展 或 修改 构建过程。 - 更好的封装性:由于建造者模式将复杂对象的构建过程 封装 在具体建造者中,客户端只需要调用
Director的construct()方法即可,无需关心具体的构建过程。 - 对象构建的精确控制:通过建造者模式,可以在
Director中 精确地 控制对象的构建过程,包括每个部分的 构建顺序、构建时的 参数设置 等,从而得到更精确的结果。
7 使用场景
- 创建的对象较 复杂,由多个部件构成,各部件面临着复杂的变化,但构件间的 建造顺序是稳定的。
- 创建复杂对象的算法 独立于 该对象的组成部分以及它们的装配方式,即产品的构建过程和最终的表现是独立的。
8 总结
建造者模式通过分离复杂对象的构建和表示,提供了更灵活、更可扩展的构建过程,是处理 复杂对象构建问题 的有效手段。
相关文章:
三、建造者模式
文章目录 1 基本介绍2 案例2.1 Car 类2.2 CarBuilder 抽象类2.3 EconomyCarBuilder 类2.4 LuxuryCarBuilder 类2.5 CarDirector 类2.6 测试程序2.7 测试结果2.8 总结 3 各角色之间的关系3.1 角色3.1.1 Product ( 产品 )3.1.2 Builder ( 抽象建造者 )3.1.3 ConcreteBuilder ( 具…...
MySQL-----索引
一、什么是索引 存储引擎用于快速找到记录的一种数据结构。 索引类似于目录。就比如我们要找书里的一段话,我们先按目录找,然后再具体定位,这样速度会很快。 二、索引的作用 通过创建唯一性索引,可以保证数据库表中每一行数据的…...
Webpack 5 Tree Shaking与Module Federation
Webpack是一个流行的JavaScript模块打包器,它在前端工程化中扮演着核心角色。Webpack 5引入了许多新特性,其中两个最值得关注的是Tree Shaking和Module Federation。这两个特性分别解决了代码体积优化和微前端架构的问题。接下来,我们将深入探…...
免费分享一套微信小程序图书馆座位预约管理系统(SpringBoot后端+Vue管理端)【论文+源码+SQL脚本】,帅呆了~~
大家好,我是java1234_小锋老师,看到一个不错的微信小程序图书馆座位预约管理系统(SpringBoot后端Vue管理端),分享下哈。 项目介绍 随着移动互联网技术的飞速发展和智能设备的普及,图书馆服务模式正在经历深刻的变革。本论文旨在…...
k8s入门:从安装到实际应用
Kubernetes (K8s) 入门指南:从安装到实际应用 Kubernetes 是一个开源的容器编排平台,用于自动化容器化应用程序的部署、扩展和管理。它能帮助你管理多个容器化应用程序,并确保它们在不同环境下的一致性和可用性。本文将介绍如何在本地环境安…...
基于Qt的上位机通用框架
0.前言 最近一年多的时间一直在开发设备控制相关的软件,加上之前在聚光的两年时间,前前后后开发这种设备控制类型的上位机软件也有三年的时间了。总结出了一套基于Qt的上位机编程框架,核心思想类似于C#的依赖注入,对象的初始化都…...
Vulnhub靶场DC-7练习
目录 0x00 准备0x01 主机信息收集0x02 站点信息收集1. 获取用户名/密码2. ssh连接目标主机3. drush命令修改Drupal密码 0x03 漏洞查找与利用1. Drupal写入php木马2. 连接shell3. 反弹shell并提权 0x04 总结 0x00 准备 下载链接:https://download.vulnhub.com/dc/DC-…...
吴恩达深度学习笔记1 Neural Networks and Deep Learning
参考视频:(超爽中英!) 2024公认最好的【吴恩达深度学习】教程!附课件代码 Professionalization of Deep Learning_哔哩哔哩_bilibili Neural Networks and Deep Learning 1. 深度学习引言(Introduction to Deep Learning) 2. 神 经 网 络 的 编 程 基 础…...
(十)Spring教程——Spring配置概述
目录 前言 1.Spring容器高层视图 2.基于XML的配置 前言 在使用Spring所提供的各项丰富而神奇的功能之前,必须在Spring IoC容器中装配好Bean,并建立好Bean和Bean之间的关联关系。Spring的配置文件已经很精简了,但是广大的开发者希望它做得更…...
飞书群聊机器人自定义机器人接入,并实现艾特@群成员功能
飞书群聊机器人还是比钉钉的要麻烦一点,钉钉的直接通过手机号就可以艾特群里面的人,但是飞书的要想艾特群里面的人,需要使用用户的 Open ID 或 User ID。这两个ID怎么获取呢?还需要在飞书的开放平台上创建一个应用,然后…...
CrowdStrike更新致850万Windows设备宕机,微软紧急救火!
7月18日,网络安全公司CrowdStrike发布了一次软件更新,导致全球大范围Windows系统宕机。 预估CrowdStrike的更新影响了将近850万台Windows设备,多行业服务因此停滞,全球打工人原地放假,坐等吃瓜,网络上爆梗…...
银行黄金交易流程
银行黄金交易流程 银行黄金交易流程通常包括以下几个步骤: 咨询和开户: 首先,客户需要到银行的贵金属交易柜台或在线平台咨询黄金交易的相关规定和手续,然后进行开户,在银行开立有关黄金交易的账户。这可能需要提供个…...
MATLAB实验五:MATLAB数据分析
1. 某线路上不同时间对应的电压如下表所示: 1)用 3 次多项式拟合(polyfit)该实验曲线,要求绘制 2 原始采样 点,并在 1~8 范围内,使用时间间隔为 0.2 的数据绘制拟合曲线。 建立一个脚本文件:text5_1.m 如下…...
Cannot perform upm operation: connect ETIMEDOUT 34.36.199.114:443 [NotFound]
版本:Unity 2018 Windows 问题:打开 Package Manager,加载报错 尝试解决: 删除项目文件里的Packages下的mainfest.json文件,然后重新打开项目(X)重新登录 Unity 账号(X)…...
Docusaurus VS VuePress:哪一个更适合你的技术文档?
💝💝💝欢迎莅临我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:「stormsha的主页」…...
昇思25天学习打卡营第25天|MindNLP ChatGLM-6B StreamChat
配置环节 %%capture captured_output !pip uninstall mindspore -y !pip install -i https://pypi.mirrors.ustc.edu.cn/simple mindspore2.2.14 !pip install mindnlp !pip install mdtex2html配置国内镜像 !export HF_ENDPOINThttps://hf-mirror.com下载与加载模型 from m…...
海康威视综合安防管理平台 detection 前台RCE漏洞复现
0x01 产品简介 海康威视综合安防管理平台是一套“集成化”、“智能化”的平台,通过接入视频监控、一卡通、停车场、报警检测等系统的设备。海康威视集成化综合管理软件平台,可以对接入的视频监控点集中管理,实现统一部署、统一配置、统一管理和统一调度。 0x02 漏洞概述 海康…...
【BUG】已解决:ModuleNotFoundError: No module named ‘PIL‘
已解决:ModuleNotFoundError: No module named ‘PIL‘ 目录 已解决:ModuleNotFoundError: No module named ‘PIL‘ 【常见模块错误】 错误原因: 解决办法: 欢迎来到英杰社区https://bbs.csdn.net/topics/617804998 欢迎来到我…...
css font 优化
文章目录 使用 font-display 控制字体加载预加载关键字体选择合适的字体文件类型按需创建字体文件HTTP 缓存优化 使用 font-display 控制字体加载 避免字体加载导致的空白 block:浏览器在短暂的阻塞期内不显示任何文本,直到字体加载完成。这可能导致页…...
Go之Web急速入门Gin+Gorm框架
简介 只作为快速入门、了解Go的GinGorm框架的demo,不能作为企业级开发。 详细用法请看官网 《Gin官网》 《Gorm官网》 使用GoLand创建Go项目(默认modules) go版本1.22.2 需要设置代理下载go相关软件包,否则软件包可能无法下载。…...
多模态2025:技术路线“神仙打架”,视频生成冲上云霄
文|魏琳华 编|王一粟 一场大会,聚集了中国多模态大模型的“半壁江山”。 智源大会2025为期两天的论坛中,汇集了学界、创业公司和大厂等三方的热门选手,关于多模态的集中讨论达到了前所未有的热度。其中,…...
【人工智能】神经网络的优化器optimizer(二):Adagrad自适应学习率优化器
一.自适应梯度算法Adagrad概述 Adagrad(Adaptive Gradient Algorithm)是一种自适应学习率的优化算法,由Duchi等人在2011年提出。其核心思想是针对不同参数自动调整学习率,适合处理稀疏数据和不同参数梯度差异较大的场景。Adagrad通…...
UE5 学习系列(三)创建和移动物体
这篇博客是该系列的第三篇,是在之前两篇博客的基础上展开,主要介绍如何在操作界面中创建和拖动物体,这篇博客跟随的视频链接如下: B 站视频:s03-创建和移动物体 如果你不打算开之前的博客并且对UE5 比较熟的话按照以…...
JAVA后端开发——多租户
数据隔离是多租户系统中的核心概念,确保一个租户(在这个系统中可能是一个公司或一个独立的客户)的数据对其他租户是不可见的。在 RuoYi 框架(您当前项目所使用的基础框架)中,这通常是通过在数据表中增加一个…...
Mysql8 忘记密码重置,以及问题解决
1.使用免密登录 找到配置MySQL文件,我的文件路径是/etc/mysql/my.cnf,有的人的是/etc/mysql/mysql.cnf 在里最后加入 skip-grant-tables重启MySQL服务 service mysql restartShutting down MySQL… SUCCESS! Starting MySQL… SUCCESS! 重启成功 2.登…...
DingDing机器人群消息推送
文章目录 1 新建机器人2 API文档说明3 代码编写 1 新建机器人 点击群设置 下滑到群管理的机器人,点击进入 添加机器人 选择自定义Webhook服务 点击添加 设置安全设置,详见说明文档 成功后,记录Webhook 2 API文档说明 点击设置说明 查看自…...
jdbc查询mysql数据库时,出现id顺序错误的情况
我在repository中的查询语句如下所示,即传入一个List<intager>的数据,返回这些id的问题列表。但是由于数据库查询时ID列表的顺序与预期不一致,会导致返回的id是从小到大排列的,但我不希望这样。 Query("SELECT NEW com…...
基于江科大stm32屏幕驱动,实现OLED多级菜单(动画效果),结构体链表实现(独创源码)
引言 在嵌入式系统中,用户界面的设计往往直接影响到用户体验。本文将以STM32微控制器和OLED显示屏为例,介绍如何实现一个多级菜单系统。该系统支持用户通过按键导航菜单,执行相应操作,并提供平滑的滚动动画效果。 本文设计了一个…...
DeepSeek越强,Kimi越慌?
被DeepSeek吊打的Kimi,还有多少人在用? 去年,月之暗面创始人杨植麟别提有多风光了。90后清华学霸,国产大模型六小虎之一,手握十几亿美金的融资。旗下的AI助手Kimi烧钱如流水,单月光是投流就花费2个亿。 疯…...
LUA+Reids实现库存秒杀预扣减 记录流水 以及自己的思考
目录 lua脚本 记录流水 记录流水的作用 流水什么时候删除 我们在做库存扣减的时候,显示基于Lua脚本和Redis实现的预扣减 这样可以在秒杀扣减的时候保证操作的原子性和高效性 lua脚本 // ... 已有代码 ...Overridepublic InventoryResponse decrease(Inventor…...
