三、建造者模式

news2024/9/20 10:57:23

文章目录

  • 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;
    }

    @Override
    public 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();
    }

    @Override
    public CarBuilder assembleEngine() {
        car.setEngine("小排量发动机");
        return this;
    }

    @Override
    public CarBuilder assembleWheel(String wheel) {
        car.setWheel(wheel);
        return this;
    }

    @Override
    public CarBuilder assembleSteeringWheel() {
        car.setSteeringWheel("常规方向盘");
        return this;
    }

    @Override
    public Car build() {
        return car;
    }
}

2.4 LuxuryCarBuilder 类

public class LuxuryCarBuilder extends CarBuilder { // 豪华型汽车建造者
    private Car car;

    public LuxuryCarBuilder() {
        this.car = new Car();
    }

    @Override
    public CarBuilder assembleEngine() {
        car.setEngine("大排量发动机");
        return this;
    }

    @Override
    public CarBuilder assembleWheel(String wheel) {
        car.setWheel(wheel);
        return this;
    }

    @Override
    public CarBuilder assembleSteeringWheel() {
        car.setSteeringWheel("带加热功能的方向盘");
        return this;
    }

    @Override
    public 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.coloradmin.cn/o/1939338.html

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

相关文章

电阻有哪些参数呢

电阻是电路中最常见的元件之一&#xff0c;它在控制电流、分压和保护电路等方面发挥着重要作用。了解电阻的主要参数对于选择和使用电阻至关重要。本文将详细介绍电阻的主要参数&#xff0c;包括电阻值、功率额定值、温度系数、容差、噪声、频率特性、体积和封装等。 1. 电阻值…

长模式下的分页

前提 如果开启了长模式&#xff0c;则必须同时开启分页模式&#xff0c;因为长模式弱化了分段模型而分段模型也确实有很多不足&#xff0c;不适应现在操作系统和应用软件的发展长模式也扩展了 CPU 的位宽&#xff0c;使得 CPU 能使用 64 位的超大内存地址空间所以&#xff0c;…

当一个程序员的博客突然变少

shigen坚持更新文章的博客写手&#xff0c;擅长Java、python、vue、shell等编程语言和各种应用程序、脚本的开发。记录成长&#xff0c;分享认知&#xff0c;留住感动。 个人IP&#xff1a;shigen hello&#xff0c;伙伴们好久不见。马上到了八月&#xff0c;也是我在个人公众号…

JMeter介绍、安装配置以及快速入门

文章目录 1. JMeter简介2. JMeter安装配置3. JMeter快速入门 1. JMeter简介 Apache JMeter是一款开源的压力测试工具&#xff0c;主要用于测试静态和动态资源&#xff08;如静态文件、服务器、数据库、FTP服务器等&#xff09;的性能。它最初是为测试Web应用而设计的&#xff…

ETAS StackM配置及使用-stack监控

文章目录 前言Stack基本介绍StackM配置StackMTargetStackMGeneral Linker配置EcuM配置RTE配置集成与测试总结 前言 嵌入式C语言执行的软件中&#xff0c;stack溢出会导致程序执行异常&#xff0c;严重可能导致直接进硬件异常中断(hardfault)。软件执行过程中的stack监控是非常…

【JAVA多线程】Future,专为异步编程而生

目录 1.Future 2.CompletableFuture 2.1.为什么会有CompletableFuture&#xff1f; 2.2.使用 2.2.1.提交任务获取结果 2.2.2.回调函数 2.2.3.CompletableFuture嵌套问题 1.Future Java中的Future接口代表一个异步计算。其提供了一组规范用来对异步计算任务进行管理控制…

java项目(knife4j使用,静态资源未放在static资源包下,公共字段自动填充,Spring Cache与Spring Task)

Knife4j&#xff08;生成接口文档&#xff09; 使用swagger你只需要按照它的规范去定义接口及接口相关的信息&#xff0c;就可以做到生成接口文档&#xff0c;以及在线接口调试页面。官网:https://swagger.io/ Knife4j是为Java MVC框架集成Swagger生成Api文档的增强解决方案。…

uni-app 影视类小程序开发从零到一 | 开源项目推荐

引言 在数字娱乐时代&#xff0c;对于电影爱好者而言&#xff0c;随时随地享受精彩影片成为一种日常需求。分享一款基于 uni-app 开发的影视类小程序。它不仅提供了丰富的影视资源推荐&#xff0c;还融入了个性化知乎日报等内容&#xff0c;是不错的素材&#xff0c;同时对电影…

Springboot同时支持http和https访问

springboot默认是http的 一、支持https访问 需要生成证书&#xff0c;并配置到项目中。 1、证书 如果公司提供&#xff0c;则直接使用公司提供的证书&#xff1b; 如果公司没有提供&#xff0c;也可自己使用Java自带的命令keytool来生成&#xff1a; &#xff08;1&#x…

JavaWeb笔记_Cookie

一.会话技术概述 在日常生活中,A和B之间在打电话过程中一连串的你问我答就是一个会话 在BS模型中,会话可以理解为通过浏览器访问服务端的资源,点击超链接可以进行资源的跳转,直到浏览器关闭过程叫做会话 我们使用会话技术可以解决的是整个会话过程中(通过浏览器浏览服务…

【Linux】一文向您详细介绍 Vim编辑器 显示行号的方法

【Linux】一文向您详细介绍 Vim编辑器 显示行号的方法 下滑即可查看博客内容 &#x1f308; 欢迎莅临我的个人主页 &#x1f448;这里是我静心耕耘深度学习领域、真诚分享知识与智慧的小天地&#xff01;&#x1f387; &#x1f393; 博主简介&#xff1a;985高校的普通本…

【Matlab】PLS偏最小二乘法回归预测算法(附代码)

资源下载&#xff1a; 资源合集&#xff1a; 目录 一&#xff0c;概述 偏最小二乘法是一种新型的多元统计数据分析方法&#xff0c;于1983年由S.Wold和C.Albano等人首次提出。偏最小二乘法实现了&#xff0c;在一个算法下&#xff0c;可以同时实现回归建模&#xff08;多元线…

类和对象:赋值函数

1.运算符重载 • 当运算符被⽤于类类型的对象时&#xff0c;C语⾔允许我们通过运算符重载的形式指定新的含义。C规定类类型对象使⽤运算符时&#xff0c;必须转换成调⽤对应运算符重载&#xff0c;若没有对应的运算符重载&#xff0c;则会编译报错&#xff1b;&#xff08;运算…

SwiftUI 5.0(iOS 17)滚动视图的滚动目标行为(Target Behavior)解惑和实战

概览 在 SwiftUI 的开发过程中我们常说&#xff1a;“屏幕不够&#xff0c;滚动来凑”。可见滚动视图对于超长内容的呈现有着多么秉轴持钧的重要作用。 这不&#xff0c;从 SwiftUI 5.0&#xff08;iOS 17&#xff09;开始苹果又为滚动视图增加了全新的功能。但是官方的示例可…

【LeetCode】80.删除有序数组中的重复项II

1. 题目 2. 分析 3. 代码 class Solution:def removeDuplicates(self, nums: List[int]) -> int:if len(nums) < 3:return len(nums)i 0j 1k 2while(k < len(nums)):if (nums[i] nums[j]):while(k < len(nums) and nums[j] nums[k] ):k1if (k < len(nums…

C语言指针超详解——最终篇一

C语言指针系列文章目录 入门篇 强化篇 进阶篇 最终篇一 文章目录 C语言指针系列文章目录1. 回调函数是什么2. qsort 函数2.1 概念2.2 qsort 排序 int 类型数据2.3 使用 qsort 排序结构体数据 3. 模拟实现 qsort 函数4. sizeof 与 strlen 的对比4.1 sizeof4.2 strlen4.3 sizeof…

ctf中php反序列化汇总

序列化与反序列化的概念 序列化就是将对象转换成字符串。字符串包括 属性名 属性值 属性类型和该对象对应的类名。 反序列化则相反将字符串重新恢复成对象。 对象的序列化利于对象的保存和传输,也可以让多个文件共享对象。 序列化举例&#xff1a;一般ctf题目中我们就是要将对…

02设置burpsuite代理

在日常工作之中&#xff0c;我们最常用的web客服端就是web浏览器&#xff0c;我们可以通过代理的设置&#xff0c;做到web浏览器的流量拦截&#xff0c;并且经过burpsuite代理的数据流量进行处理。 在火狐浏览器中安装foxyporxy

哥德尔不完备定理(Godel‘s Incompleteness Theorem) —— 奠定了计算机与 AI 的理论基础

哥德尔不完备定理 在数理逻辑中&#xff0c;哥德尔不完备定理是指库尔特・哥德尔于 1931 年证明并发表的两条定理。简单地说&#xff0c;第一条定理指出&#xff1a;任何相容的形式系统&#xff0c;只要蕴涵皮亚诺算术公理&#xff0c;就可以在其中构造在体系中既不能证明也不…

Java GC(垃圾回收)机制详解

Java GC&#xff08;垃圾回收&#xff09;机制详解 1、GC触发的条件2、GCRoots的对象类型 &#x1f496;The Begin&#x1f496;点点关注&#xff0c;收藏不迷路&#x1f496; 在Java的世界里&#xff0c;内存管理是自动进行的&#xff0c;其中垃圾回收&#xff08;Garbage Col…