【设计模式】创建型-建造者模式

前言

在面向对象的软件开发中,构建复杂对象时经常会遇到许多挑战。一种常见的解决方案是使用设计模式,其中建造者模式是一个强大而灵活的选择。本文将深入探讨建造者模式的原理、结构、优点以及如何在实际项目中应用它。

一、复杂的对象

public class Computer {private String ram;private String hardDisk;private String cpu;// ...可能还有更多参数...public Computer(String ram, String hardDisk, String cpu) {this.ram = ram;this.hardDisk = hardDisk;this.cpu = cpu;// ...初始化更多参数...}// getters and setters...
}// 使用构造函数创建对象,参数多且容易混淆
Computer computer = new Computer("16GB", "1TB", "Intel i7");

上面代码比较简单,但是如果 Computer 类有更多的参数,构造函数将会变得非常长,而且在创建 Computer 对象时,传递参数的顺序非常重要,一旦顺序错误,就会创建出一个配置错误的对象。此外,如果参数有默认值,那么用户还需要记住哪些参数是必须的,哪些是可选的,这增加了使用的复杂性。

我们可以总结出创建复杂对象时可能会遇到的问题包括:

  1. 参数过多:构造函数或者 setter 方法的参数可能会非常多,导致代码难以阅读和维护。
  2. 参数顺序:容易混淆参数的顺序,特别是当有多个相同类型的参数时。
  3. 不够灵活:如果创建过程中需要多个步骤,使用构造函数或 setter 方法就不够灵活。
  4. 不可读性:代码的可读性差,特别是在没有注释的情况下,很难理解每个参数的意义。

二、建造者模式

建造者模式是一种创建型设计模式,旨在将复杂对象的构建过程与其表示分离。通过使用建造者模式,可以使客户端代码与对象的内部结构解耦,从而使构建过程更加灵活,并且更易于维护和扩展。

三、建造者模式的核心组成部分

在这里插入图片描述

建造者模式通常包括以下几个关键组件:

  1. 产品(Product):表示被构建的复杂对象。产品类通常包含多个属性,并且可能包含一些复杂的业务逻辑。
  2. 抽象建造者(Builder):定义了构建产品所需的接口。抽象建造者通常包括一系列方法来构建产品的各个部分。
  3. 具体建造者(Concrete Builder):实现了抽象建造者接口,负责实际构建产品的各个部分,并提供方法来获取最终的产品实例。
  4. 指挥者(Director):负责调用建造者的方法来构建产品,但不直接创建产品的实例。指挥者通常根据一定的构建步骤来组织构建过程。

四、运用建造者模式

场景假设:我们要构建一台计算机,它有不同的部件,比如 CPU、内存、硬盘等。我们将使用建造者模式来构建这台计算机。

  1. 定义产品类: 首先,确定需要构建的复杂对象的属性和方法,并创建相应的产品类。这个产品类应该包含对象的所有属性,并提供相应的 getter 和 setter 方法。

    /*** 产品类:计算机*/
    public class Computer {private String cpu;       // CPUprivate String memory;    // 内存private String hardDisk;  // 硬盘// 省略构造函数和 getter/setter方法
    }
    
  2. 创建抽象建造者接口: 定义一个抽象建造者接口,该接口包含构建产品各个部件的抽象方法。这些方法代表构建产品所需的不同步骤。

    /*** 抽象建造者接口*/
    public interface ComputerBuilder {// 构建CPUvoid buildCPU();// 构建内存void buildMemory();// 构建硬盘void buildHardDisk();// 构建计算机Computer build();
    }
    
  3. 实现具体建造者类: 创建一个或多个具体建造者类,实现抽象建造者接口。每个具体建造者类负责实现构建产品各个部件的具体方法,并在最后返回构建好的产品。

    /*** 具体建造者类:桌面计算机建造者*/
    public class DesktopComputerBuilder implements ComputerBuilder {private Computer computer;  // 待构建的计算机对象public DesktopComputerBuilder() {this.computer = new Computer();}@Overridepublic void buildCPU() {computer.setCpu("Intel Core i7");}@Overridepublic void buildMemory() {computer.setMemory("16GB DDR4");}@Overridepublic void buildHardDisk() {computer.setHardDisk("1TB SSD");}@Overridepublic Computer build() {// 返回构建好的计算机对象return computer;}
    }
    
  4. 创建指挥者类: 定义一个指挥者类,该类负责使用具体建造者对象构建最终的产品。指挥者类知道构建者的具体实现细节,但与产品的实际构建过程无关。

    /*** 指挥者类:计算机指挥者*/
    public class ComputerDirector {private ComputerBuilder computerBuilder;  // 建造者对象public ComputerDirector(ComputerBuilder computerBuilder) {this.computerBuilder = computerBuilder;}// 使用建造者构建计算机对象public Computer construct() {// 按照顺序调用建造者的方法来构建计算机computerBuilder.buildCPU();computerBuilder.buildMemory();computerBuilder.buildHardDisk();// 返回构建好的计算机对象return computerBuilder.build();}
    }
    
  5. 使用建造者模式构建对象: 在客户端代码中,创建具体的建造者对象,并将其传递给指挥者类。然后,通过指挥者类调用相应的方法来构建产品。最终,客户端代码可以获取构建好的产品并使用它。

    public class Main {public static void main(String[] args) {// 创建桌面计算机的建造者对象ComputerBuilder desktopBuilder = new DesktopComputerBuilder();// 创建计算机指挥者对象,并传入桌面计算机的建造者ComputerDirector director = new ComputerDirector(desktopBuilder);// 使用指挥者构建计算机对象Computer desktop = director.construct();// 输出构建好的桌面计算机的配置信息System.out.println("Desktop Computer Configuration:");System.out.println(desktop);}
    }/*在一些简单的情况下,可以省略指挥者(Director)类。特别是当只有一个具体建造者(Concrete Builder)时,客户端代码可以直接调用具体建造者的方法来构建产品,而不需要指挥者类。
    */
    public class Main {public static void main(String[] args) {// 创建桌面计算机的建造者对象ComputerBuilder desktopBuilder = new DesktopComputerBuilder();// 使用桌面计算机的建造者直接构建计算机对象Computer desktop = desktopBuilder.buildCPU().buildMemory().buildHardDisk().build();// 输出构建好的桌面计算机的配置信息System.out.println("Desktop Computer Configuration:");System.out.println(desktop);}
    }
    

在上面的例子中,我们定义了 Computer 类作为产品,ComputerBuilder 作为具体建造者来创建产品,ComputerDirector 作为指导者确定创建产品时遵循的步骤流程。客户端代码只需通过 ComputerDirector 便能构建 Computer 对象,这样就隐藏了构建细节,使得客户端代码更加简洁和易于维护。

五、建造者模式的应用场景

建造者模式适用于以下几种场景:

  1. 复杂对象的创建:当创建的对象非常复杂,包含多个组成部分时,建造者模式可以帮助管理复杂性,使得代码更加清晰。

    // 假设我们需要创建一个复杂的 Pizza 对象,它包含多种配料和选项。
    // 产品类
    public class Pizza {private String dough;private String sauce;private String topping;// 私有构造器private Pizza(Builder builder) {this.dough = builder.dough;this.sauce = builder.sauce;this.topping = builder.topping;}// Builder类public static class Builder {private String dough;private String sauce;private String topping;public Builder withDough(String dough) {this.dough = dough;return this;}public Builder withSauce(String sauce) {this.sauce = sauce;return this;}public Builder withTopping(String topping) {this.topping = topping;return this;}public Pizza build() {return new Pizza(this);}}
    }// 客户端代码
    // 在创建 Pizza 时,可以根据需要选择是否设置 dough、sauce、topping
    Pizza pizza = new Pizza.Builder().withDough("cross").withSauce("mild").withTopping("ham and pineapple").build();
    
  2. 构造过程需要分步骤进行:如果一个对象的构造过程需要分多个步骤或者阶段来完成,建造者模式允许你逐步构造对象,而不是一次性通过一个巨大的构造函数完成。

    // 倘若 House 对象的构建,需要分步骤设置地基、结构、屋顶和内部装修。
    // 产品类
    public class House {private String foundation;private String structure;private String roof;private String interior;private House(Builder builder) {this.foundation = builder.foundation;this.structure = builder.structure;this.roof = builder.roof;this.interior = builder.interior;}// Builder类public static class Builder {private String foundation;private String structure;private String roof;private String interior;public Builder withFoundation(String foundation) {this.foundation = foundation;return this;}public Builder withStructure(String structure) {this.structure = structure;return this;}public Builder withRoof(String roof) {this.roof = roof;return this;}public Builder withInterior(String interior) {this.interior = interior;return this;}public House build() {return new House(this);}}
    }// 客户端代码
    // 在创建对象之前,可严格管控步骤的先后顺序
    House house = new House.Builder().withFoundation("concrete").withStructure("wooden").withRoof("shingle").withInterior("painted").build();
    
  3. 同一构建过程不同表示:当需要根据不同的需求和过程来创建不同的对象表示时,建造者模式提供了很好的解决方案。

    // 如果我们有一个 Car 对象,它可以有不同的配置,例如经济型和豪华型。
    // 产品类
    public class Car {private String engine;private String seats;private String navigationSystem;private Car(Builder builder) {this.engine = builder.engine;this.seats = builder.seats;this.navigationSystem = builder.navigationSystem;}// Builder类public static class Builder {private String engine;private String seats;private String navigationSystem;public Builder withEngine(String engine) {this.engine = engine;return this;}public Builder withSeats(String seats) {this.seats = seats;return this;}public Builder withNavigationSystem(String navigationSystem) {this.navigationSystem = navigationSystem;return this;}public Car build() {return new Car(this);}}
    }// 客户端代码
    // 根据不同配置,满足不同需求
    Car economyCar = new Car.Builder().withEngine("1.5L").withSeats("cloth").build();Car luxuryCar = new Car.Builder().withEngine("3.0L V6").withSeats("leather").withNavigationSystem("advanced").build();
    
  4. 参数多且复杂:当构造函数的参数非常多,且有些可能是可选的,建造者模式可以帮助组织这些参数,使得构造函数不会过于庞大和复杂。

    // 倘若 Order 对象可能包含多个可选的配置项,如礼品包装、快递服务、优惠券等,
    // 使用建造者模式可以让客户端代码清晰地指定所需的配置。
    // 产品类:具有多个配置参数,其中一些是可选的。
    public class Order {private String product;private boolean giftWrap;private boolean expressDelivery;private String couponCode;// 私有构造器,只能通过Builder类构建Order对象private Order(Builder builder) {this.product = builder.product;this.giftWrap = builder.giftWrap;this.expressDelivery = builder.expressDelivery;this.couponCode = builder.couponCode;}// Builder 类:提供了一个链式 API 来设置 Order 对象的属性public static class Builder {private String product;private boolean giftWrap;private boolean expressDelivery;private String couponCode;public Builder(String product) {this.product = product;}public Builder setGiftWrap(boolean giftWrap) {this.giftWrap = giftWrap;return this;}public Builder setExpressDelivery(boolean expressDelivery) {this.expressDelivery = expressDelivery;return this;}public Builder setCouponCode(String couponCode) {this.couponCode = couponCode;return this;}// 构建方法:创建一个Order对象并返回public Order build() {return new Order(this);}}
    }// 客户端使用:创建一个 Order 对象
    Order order = new Order.Builder("Product1").setGiftWrap(true).setExpressDelivery(true).setCouponCode("DISCOUNT10").build();
    

六、小结

建造者模式是一种创建复杂对象的有效方式,它允许我们按照步骤构建对象,从而使得构建过程更加灵活和可配置。例如,在 Java 中,StringBuilder 是建造者模式的一个典型应用,它允许我们通过多个方法调用来构建最终的字符串,而不是一次性传入所有的字符串内容。另一个例子是流式 API,如 Java 8 的 Stream API,它允许通过链式调用来构建复杂的查询。通过将构建过程与表示分离,建造者模式提高了代码的可读性和可维护性,同时也使得代码更加易于扩展和重用。

推荐阅读

  1. Spring 三级缓存
  2. 深入了解 MyBatis 插件:定制化你的持久层框架
  3. Zookeeper 注册中心:单机部署
  4. 【JavaScript】探索 JavaScript 中的解构赋值
  5. 深入理解 JavaScript 中的 Promise、async 和 await

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

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

相关文章

vue3学习使用笔记

1.学习参考资料 vue3菜鸟教程:https://www.runoob.com/vue3/vue3-tutorial.html 官方网站:https://cn.vuejs.org/ 中文文档: https://cn.vuejs.org/guide/introduction.html Webpack 入门教程:https://www.runoob.com/w3cnote/webpack-tutor…

手机离线翻译哪个好?断网翻译也能超丝滑

有时在异国他乡,面对语言不通的窘境,即便是简单的对话也变得异常困难,真是挑战满满! 然而,能离线翻译的软件让语言障碍不再是问题,不必依赖网络也能轻松进行翻译啦~ 只需下载所需的语言包,选择…

Nginx企业级负载均衡:技术详解系列(14)—— 账户认证功能

你好,我是赵兴晨,97年文科程序员。 你有没有听说过Nginx的账户认证功能?这可不只是一个技术问题,它关系到我们上网时的安全和便利。就像家里需要一把钥匙才能进们一样,Nginx的账户认证功能就是确保有只有授权的人才能…

登录校验及全局异常处理器

登录校验 会话技术 会话:用户打开浏览器,访问web服务器的资源,会话建立,直到有一方断开连接,会话结束.在一次会话中可以包含多次请求和响应会话跟踪:一种维护浏览器状态的方法,服务器需要识别多次请求是否来自于同一浏览器,以便在同一次会话请求间共享数据会话跟踪方案 客户端…

华为 CANN

华为 CANN 1 介绍1.1 概述1.2 CANN 是华为昇腾计算产业的重要一环1.3 昇腾系列处理器1.4 昇腾 AI 产业1.5 从 AI 算法到产品化落地流程1.6 多样性计算架构1.7 人工智能各层级图示1.8 人工智能技术发展历史 2 CANN vs CUDA支持平台优化方向编程接口生态系统与应用性能与功能 3 C…

Qt xml学习之calculator-qml

1.功能说明:制作简易计算器 2.使用技术:qml,scxml 3.项目效果: 4.qml部分: import Calculator 1.0 //需要引用对应类的队友版本 import QtQuick 2.12 import QtQuick.Window 2.12 import QtQuick.Controls 1.4 import QtScxml…

[深度学习]yolov10+bytetrack+pyqt5实现目标追踪

【简介】 利用YOLOv10、ByteTrack和PyQt5实现目标追踪是一个强大的组合,可以为用户提供一个交互式的实时目标追踪界面。以下是一个简化版的实现思路描述: 首先,YOLOv10是一个先进的目标检测算法,能够准确识别视频或图像中的目标…

OC IOS 文件解压缩预览

热很。。热很。。。。夏天的城市只有热浪没有情怀。。。 来吧,come on。。。 引用第三方库: pod SSZipArchive 开发实现: 一、控制器实现 头文件控制器定义: // // ZipRarViewController.h // // Created by carbonzhao on 2…

更新mirh connect 内置derby数据库密码

更新mirh connect 内置derby数据库密码 1、下载derby连接客户端 https://archive.apache.org/dist/db/derby/ 选择任意版本即可,比如 https://archive.apache.org/dist/db/derby/db-derby-10.14.2.0/db-derby-10.14.2.0-bin.zip 2、连接mirh文件数据库 1、把mi…

12 FreeRTOS 调试与优化

1、调试 1.1 打印 在FreeRTOS工程中使用了microlib,里面实现了printf函数。 只需要实现一下以下函数即可使用printf。 int fputc(int ch; FILE *f); 假如要从串口实现打印函数: int fputc( int ch, FILE *f ) {//指定串口USART_TypeDef* USARTx USAR…

黑马一站制造数仓实战2

问题 DG连接问题 原理:JDBC:用Java代码连接数据库 Hive/SparkSQL:端口有区别 可以为同一个端口,只要不在同一台机器 项目:一台机器 HiveServer:10000 hiveserver.port 10000 SparkSQL:10001…

如何克隆非默认分支

直接git clone下来的我们知道是默认分支,那如何克隆其他分支呢: 比如这个,我们想克隆AdvNet。 我们可以在本地文件夹打开Git Bash 依次输入: git clone --branch AdvNet https://github.com/wgcban/SemiCD.git cd SemiCD git b…

Java基础入门day62

day62 AJAX 概念 AJAX: Asynchronous Javascript And XML AJAX是一种无需重新加载整个网页的情况下,能够更新部分网页的技术 AJAX是一种用于创建快速动态网页的技术 通过在后台与服务器进行少量数据交换,AJAX可以使网页实现异步更新 传统…

源码编译安装LAMP(安装apeche mysql php 论坛 网站 巨详细版)

目录 一.LAMP架构相关概述 1.各组件作用 Linux(平台) Apache(前台) MySQL(后台) PHP/Perl/Python(中间连接) 总结 二.编译安装Apache httpd服务 1.关闭防火墙,将…

docker一键部署EFK系统(elasticsearch filebeat kibana metricbeat es-head)

EFK日志系统搭建 EFK日志系统介绍功能需求搭建elasticsearch集群规划前提部署核对证书及权限 EFK日志系统介绍 Elasticsearch 是一个实时的、分布式的可扩展的搜索引擎,允许进行全文、结构化搜索,它通常用于索引和搜索大量日志数据,也可用于…

【计算机网络】——物理层(图文并茂)

物理层 一.物理层概述1.物理层要实现的功能2.物理层接口特征1.机械特性2.电气特性3.功能特性4.过程特性 二.物理层下面的传输媒体1.传输媒体的分类2.导向型传输媒体1.同轴电缆2.双绞线3.光纤 3.非导向型传输媒体1.无线电波2.微波3.红外线4.激光5.可见光 三.传输方式1.串行传输与…

Kali : 安装Google Chrome 浏览器和ChromeDriver

目录 一、安装Google Chrome 浏览器 1、下载Google Chrome 2、安装Chrome 3、安装依赖包 二、安装ChromeDriver 1、查看Chrome版本 ​2、下载ChromeDriver 3、解压下载包 4、设置全局访问 5、赋予可执行权限 6、验证chromedriver 7、程序测试 一、安装Google Chrom…

Kafka系列之高频面试题

基础 简介 特点: 高吞吐、低延迟:kafka每秒可以处理几十万条消息,延迟最低只有几毫秒,每个Topic可以分多个Partition,Consumer Group对Partition进行Consumer操作可扩展性:Kafka集群支持热扩展持久性、可…

WEB攻防-JAVAWEB项目常见漏洞

知识点 1.JavaWeb常见安全及代码逻辑 2.目录遍历&身份验证&逻辑&JWT 3.访问控制&安全组件&越权&三方组件 本篇主要了解以上问题在javaweb中的呈现, 第一个重点理解URL与javaweb代码框架的对应方式,java在没有代码的情况下是很难…

【R基础】如何开始学习R-从下载R及Rstudio开始

文章目录 概要下载R流程下载Rstudio流程下载完成-打开 概要 提示:如何开始学习R-从下载R及Rstudio开始,此处我只是想下载指定版本R4.3.3 下载R流程 链接: R官网 文件下载到本地 下载文件展示 按照向导指示安装 下载Rstudio流程 链接: Rstudio官网…