三、建造者模式

文章目录

  • 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 类图

alt text
说明:这是 传统的 建造者模式的类图,如果希望支持 链式编程,则可以把建造者的所有 buildPart() 方法的返回值从 void 改为 Builder。另外,这些 buildPart() 方法不一定没有参数,根据实际情况而定。

4 注意事项

  1. 抽象建造者 的设计应包含产品 所有 部件的创建和装配方法,确保每个具体建造者都实现这些方法(使用 abstract 关键字修饰)。
  2. 具体建造者 的编写应根据产品的 组成部分组装顺序 来实现抽象建造者接口。
  3. 指挥者 需要根据 一定的逻辑和顺序 来调用具体建造者的方法,以组织产品的创建过程。

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 建造对象的代码)的前提下,新增 或 替换 具体建造者,从而 扩展 或 修改 构建过程。
  • 更好的封装性:由于建造者模式将复杂对象的构建过程 封装 在具体建造者中,客户端只需要调用 Directorconstruct() 方法即可,无需关心具体的构建过程。
  • 对象构建的精确控制:通过建造者模式,可以在 Director精确地 控制对象的构建过程,包括每个部分的 构建顺序、构建时的 参数设置 等,从而得到更精确的结果。

7 使用场景

  • 创建的对象较 复杂,由多个部件构成,各部件面临着复杂的变化,但构件间的 建造顺序是稳定的
  • 创建复杂对象的算法 独立于 该对象的组成部分以及它们的装配方式,即产品的构建过程和最终的表现是独立的。

8 总结

建造者模式通过分离复杂对象的构建和表示,提供了更灵活、更可扩展的构建过程,是处理 复杂对象构建问题 的有效手段。

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

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

相关文章

SvelteKit - 1. 初始化项目

官方 doc - create a project 1、基本环境 &#xff08;下面是我这里的环境&#xff0c;亲测用 node 14 和 16 install 会报错&#xff09; node&#xff1a;20.9.0 npm&#xff1a;10.1.0 2、初始化项目 npm create sveltelatest my-app cd my-app npm install npm run de…

批量打断相交线——ArcGIS 解决方法

在数据处理&#xff0c;特别是地理空间数据处理或是任何涉及图形和线条分析的场景中&#xff0c;有时候需要把相交的线全部从交点打断一个常见的需求。这个过程对于后续的分析、编辑、或是可视化展现都至关重要&#xff0c;因为它可以确保每条线都是独立的&#xff0c;避免了因…

Vue Router基础

Router 的作用是在单页应用&#xff08;SPA&#xff09;中将浏览器的URL和用户看到的内容绑定起来。当用户在浏览不同页面时&#xff0c;URL会随之更新&#xff0c;但页面不需要从服务器重新加载。 1 Router 基础 RouterView RouterView 用于渲染当前URL路径对应的路由组件。…

pytest的安装和介绍和 Exit Code 含义

pytest 准备工作&#xff08;在cmd里&#xff09;&#xff1a; 1安装 pip install -U pytest2验证安装 pytest --version # 会展示当前已安装版本3其他的 显示可用的内置函数参数 pytest --fixtures通过命令行查看帮助信息及配置文件选项 pytest --help一、pytets框架中的…

【DVWA靶场】Web安全之(布尔值/延时型)SQL盲注(超详细教程)

SQL盲注原理 1.SQL盲注概念 SQL Injection(Blind),即SQL盲注,与一般注入的区别在于,一般的注入攻击者可以直接从页面上看到注入语句的执行结果,而盲注时攻击者通常是无法从显示页面上获取执行结果,甚至连注入语句是否执行都无从得知,因此盲注的难度要比一般注入高。目…

【数据结构】AVL树(平衡二叉搜索树)

文章目录 1.AVL树1.1 AVL树的概念1.2 AVL树节点的定义1.3 AVL树的插入1.4 AVL树的旋转1.4.1 左单旋1.4.2 右单旋1.4.3 右左双旋1.4.4 左右双旋 1.5 AVL树的平衡验证1.6 AVL树的删除1.7 AVL树的性能 1.AVL树 在前面&#xff0c;我们已经介绍过了二叉搜索树&#xff0c;也了解到…

美摄科技企业级视频拍摄与编辑SDK解决方案

在数字化浪潮汹涌的今天&#xff0c;视频已成为企业传递信息、塑造品牌、连接用户不可或缺的强大媒介。为了帮助企业轻松驾驭这一视觉盛宴的制作过程&#xff0c;美摄科技凭借其在影视级非编技术领域的深厚积累&#xff0c;推出了面向企业的专业视频拍摄与编辑SDK解决方案&…

Mac安装Hoomebrew与升级Python版本

参考 mac 安装HomeBrew(100%成功)_mac安装homebrew-CSDN博客 /bin/zsh -c "$(curl -fsSL https://gitee.com/cunkai/HomebrewCN/raw/master/Homebrew.sh)" 安装了Python 3.x版本&#xff0c;你可以使用以下命令来设置默认的Python版本&#xff1a; # 首先找到新安…

THS配置keepalive(yjm)

启动完THS管理控制台和THS后&#xff0c;登录控制台&#xff0c;进入实例管理》节点管理&#xff0c;可以分别使用界面配置和编辑配置设置长连接。 1、界面配置 点击界面配置》集群设置&#xff0c;启用长连接&#xff0c;设置长连接数、最大请求数和超时时间。 2、编辑配置 …

项目的纪要

ai客服项目中发现的问题: 可以在控制台看到我们存储的cookie: 可以看到是这样的, 但是我们通过getCookie方法专门获取这个字段, 然后在控制台打印后 const userName getTheCookie(SA_USER_NICK_NAME); console.log(userName, userName); 输出结果是: 然后我们尝试通过…

JMeter的使用方法及https的使用方法

软件安装&#xff1a; 参考链接&#xff1a;JMeter 下载安装及环境配置&#xff08;包含jdk1.8安装及配置&#xff09;_jmeter5.2.1需要什么版本的jdk-CSDN博客 前置知识储备&#xff1a; Https请求的案例: JMeter的第一个案例 增加线程数 线程&#xff08;thread&#xff…

Meta 发布 LLAMA 3.1;特斯拉无人出租车推迟至 10 月;谷歌将向 Waymo 再投 50 亿美元

先瞧一下 Chat 和 Agent 的差异。 Chat&#xff08;聊天&#xff09;&#xff1a;纯粹的 Chat&#xff0c;宛如一个主要由“大脑与嘴”组成的智能体&#xff0c;着重于信息处置和语言沟通。诸如 ChatGPT 这般的系统&#xff0c;其能够领会用户的询问&#xff0c;给出有益且连贯…

Linux:基础命令学习

目录 一、ls命令 实例&#xff1a;-l以长格式显示文件和目录信息 实例&#xff1a;-F根据文件类型在列出的文件名称后加一符号 实例&#xff1a; -R 递归显示目录中的所有文件和子目录。 实例&#xff1a; 组合使用 Home目录和工作目录 二、目录修改和查看命令 三、mkd…

《Java初阶数据结构》----4.<线性表---Stack栈和Queue队列>

前言 大家好&#xff0c;我目前在学习java。之前也学了一段时间&#xff0c;但是没有发布博客。时间过的真的很快。我会利用好这个暑假&#xff0c;来复习之前学过的内容&#xff0c;并整理好之前写过的博客进行发布。如果博客中有错误或者没有读懂的地方。热烈欢迎大家在评论区…

DAMA学习笔记(七)-数据集成和互操作

1.引言 数据集成和互操作(DII)描述了数据在不同数据存储、应用程序和组织这三者内部和之间进行移动和整合的相关过程。数据集成是将数据整合成物理的或虚拟的一致格式。数据互操作是多个系统之间进行通信的能力。数据集成和互操作的解决方案提供了大多数组织所依赖的基本数据管…

Unity XR Interaction Toolkit设置或监听手柄按键事件(三)

提示&#xff1a;文章有错误的地方&#xff0c;还望诸位大神不吝指教&#xff01; 文章目录 前言一、XRI Default Input Actions1.导入官方案例2.设置控制器绑定&#xff0c;如手柄、主/辅助按钮、操纵杆等1.要设置控制器绑定&#xff0c;如左右手 手柄、主/辅助按钮、操纵杆等…

[k8s源码]8.deltaFIFO

deltaFIFO DeltaFIFO: 这是一个特殊类型的队列&#xff0c;它结合了FIFO&#xff08;先进先出&#xff09;队列的特性和增量&#xff08;Delta&#xff09;处理的能力。DeltaFIFO 中是按顺序存储的&#xff0c;但它们不必严格按照发生的顺序逐个处理。这种设计提供了处理的灵…

【C++中线程学习】

1、多线程 C11之前没有引入线程的概念&#xff0c;如果想要实现多线程&#xff0c;需要借助操作系统平台提供的API&#xff0c;比如Linux的<pthead.h>&#xff0c;或者windows下的<windows.h>。 C11提供了语言层面上的多线程&#xff0c;包含在头文件<thread.h…

在Windows下部署jar包,关闭命令提示符可以后台运行

前言 大多数情况下&#xff0c;都是选用Linux作为服务器部署服务&#xff0c;在Linux中通过以下命令运行 nohup java -jar xxxxx-1.0-SNAPSHOT.jar 但是有时由于其他原因&#xff0c;或本地测试&#xff0c;或云服务器使用Windows server等等&#xff0c;需要在Windows上面运…

matlab仿真 数字基带传输(下)

&#xff08;内容源自详解MATLAB&#xff0f;SIMULINK 通信系统建模与仿真 刘学勇编著第六章内容&#xff0c;有兴趣的读者请阅读原书&#xff09; clear all Fd1;%符号采样频率 Fs10;%滤波器采样频率 r0.2;%滤波器滚降系数 delay4;%滤波器时延 [num,den]rcosine(Fd,Fs,defau…