设计模式之建造者模式:灵活可扩展的对象创建过程

news2024/11/18 2:48:14

目录

一、什么是建造者模式

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

三、建造者模式的优缺点

3.1. 优点

3.2. 缺点

四、建造者模式示例

4.1. 问题描述

4.2. 问题分析

4.3. 代码实现

五、建造者模式的另一种实现方式

六、总结


一、什么是建造者模式

    建造者模式(Builder Pattern)是一种创建型设计模式(Creational Pattern),可以将部件和其组装过程分开,一步一步创建一个复杂的对象。用户只需要指定复杂对象的类型就可以得到该对象,而无须知道其内部的具体构造细节。它提供了一种更加灵活和可扩展的方式来创建对象,同时也避免了构造函数参数过多导致的代码可读性和维护性问题。

    建造者模式主要包含以下四类角色:

  • 产品(Product):表示被构建的复杂对象。通常包含多个部分,具体部分的创建由具体建造者负责。
  • 抽象建造者(Builder):定义了创建产品各个部分的抽象接口,以及返回产品的方法。
  • 具体建造者(Concrete Builder):实现了抽象建造者接口,负责具体部分的创建,并返回一个组装好的产品。
  • 指挥者(Director):调用具体建造者来创建产品对象,并控制构建过程的顺序。

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

        建造者模式创建的是复杂对象,其产品的各个部分经常面临较大变化,但将它们组合在一起的算法却相对稳定,所以它适用于以下情况:

  • 当对象的构建过程较为复杂,包含多个步骤或者需要按照一定顺序构建时。
  • 当需要创建的对象具有多个表示,但构建过程相同时,可以使用建造者模式。
  • 当需要创建的对象具有复杂的内部结构,且需要按照一定的步骤进行构造时,可以使用建造者模式。

三、建造者模式的优缺点

3.1. 优点

  • 封装性:建造者模式将对象的构建过程和表示过程分离,客户端只需要知道产品的类型以及包含哪些部分,而不需要知道内部的具体构建细节。这样可以更好地封装对象,提高代码的可读性和可维护性。
  • 可扩展性:建造者模式允许在不修改已有代码的情况下扩展新的产品部件,只需要增加新的具体建造者类即可。这样可以提高系统的可扩展性,降低维护成本。
  • 清晰性:通过将构建过程分解为多个步骤,使得构建过程更加清晰,便于维护和理解。
  • 灵活性:客户端不必知道产品内部组成的细节,建造者可以对创建过程逐步细化,而不对其它模块产生任何影响。

3.2. 缺点

  • 产品的组成部分必须相同:建造者模式要求所有产品都具有相同的组成部分,这在一定程度上限制了其使用范围。如果某些产品需要特殊的构建过程或者组成部分不同,那么这种模式可能就不适用。
  • 产品内部变化复杂时维护成本较高:如果产品的内部变化复杂,那么当产品内部发生变化时,所有的Builder类都需要同步修改,这可能会导致维护成本较高。

四、建造者模式示例

4.1. 问题描述

    假设我们要制造一辆汽车,汽车由车身、引擎、轮胎等部件组成。汽车的不同部件都有不同的规格可供选择,如何通过代码来实现汽车的构建过程。

4.2. 问题分析

    问题的目的是要通过代码来创建汽车的实例对象,汽车的组成都是由车身、引擎等部件构成,只是不同部件有不同的表示(规格),这就符合了建造者模式的使用场景。问题当中的汽车(Car)显然就是我们建造者模式中的产品(Product),汽车中需要有多个部件:车身(body)、引擎(engine)、轮胎(tire),为了统一创建汽车的功能接口,我们定义其抽象建造者(Builder)为汽车建造者(CarBuilder),最后定义一个汽车建造指挥者(CarDirector)用来协调建造过程,当我们有了一个新的产品时,就可以通过新增一个汽车创建者的实现类来完成新产品的组成定义,比如有一个汽车产品A,其车身为碳纤维(carbon fibre)的,引擎是电动的(electric),轮胎是充气橡胶的(inflatable rubber),那么我们就可以新增一个A款汽车的建造者(CarABuilder)来实现这款汽车对象的创建。

4.3. 代码实现

    经过上一步的分析之后,下面我们通过代码来实现它:

/**
 * 定义汽车类
 */
class Car{
    private String body;
    private String engine;
    private String tire;
​
    public String getBody() {
        return body;
    }
​
    public void setBody(String body) {
        this.body = body;
    }
​
    public String getEngine() {
        return engine;
    }
​
    public void setEngine(String engine) {
        this.engine = engine;
    }
​
    public String getTire() {
        return tire;
    }
​
    public void setTire(String tire) {
        this.tire = tire;
    }
}
​
/**
 * 汽车创建者接口
 */
interface CarBuilder{
    void buildBody();
    void buildEngine();
    void buildTire();
    Car getCar();
}
​
/**
 * 汽车创建指挥者
 */
class CarDirector{
    private final CarBuilder carBuilder;
    public CarDirector(CarBuilder carBuilder){
        this.carBuilder = carBuilder;
    }
    public Car construct(){
        carBuilder.buildBody();
        carBuilder.buildEngine();
        carBuilder.buildTire();
        return carBuilder.getCar();
    }
}
​
/**
 * A型号汽车创建者
 */
class CarABuilder implements CarBuilder{
    private final Car car = new Car();
    @Override
    public void buildBody() {
        car.setBody("carbon fibre");
    }
    @Override
    public void buildEngine() {
        car.setEngine("electric");
    }
    @Override
    public void buildTire() {
        car.setTire("inflatable rubber");
    }
    @Override
    public Car getCar() {
        return car;
    }
}

    当我们需要创建一个A型号的汽车的对象时,我们只需要这样做就可以了:

Car carA = new CarDirector(new CarABuilder()).construct();

五、建造者模式的另一种实现方式

    当一个对象的属性过多时,通过常规的实例化方法实现的代码的可读性会非常差,并且还需要使用者对内部的所有属性都有一定的了解,此时我们可以通过给这个类专门写一个内部类作为建造者的方式将一些创建逻辑或者约束条件封装到建造者内部,使使用者可以较为简单地创建复杂对象。

    我们以java.util包下的抽象类Calendar为例,打开Calendar类,我们可以发现里面有大量的属性:

    并且作为抽象类,Calendar类还会有不同的实现:

    如果没有建造者的话,在创建一个Calendar的对象的时候无疑是很头疼的。所以Calendar类内部为我们提供了一个建造者:

    通过这个建造者我们就可以很轻松地创建一个Calendar类的实例了:

Calendar.Builder builder = new Calendar.Builder();
builder.setCalendarType("iso8601");
builder.setDate(2024, 3, 6);
Calendar calendar = builder.build();
System.out.println(calendar.getTime());

六、总结

    建造者模式是一种非常有用的设计模式,它可以帮助我们更好地组织复杂对象的构建过程,提高代码的可读性和可维护性。通过将构建过程与表示分离,建造者模式使得对象的创建变得更加灵活和可控。在实际项目中,我们可以根据具体需求来选择是否使用建造者模式,以提高代码的质量和可扩展性。

    希望通过本文的介绍,您对建造者模式有了更深入的理解,能够在实际项目中灵活运用。谢谢阅读!

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

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

相关文章

Prefetch

Prefetch &#xff08;<link rel"prefetch">&#xff09; 是一种浏览器优化&#xff0c;它允许我们在需要后续路由或页面之前获取可能需要的资源。可以通过几种方式实现预取。它可以在 HTML 中以声明方式完成&#xff08;例如在下面的示例中&#xff09;&#…

设计模式——桥接模式07

桥接模式是将抽象部分与实现部分分离&#xff0c;可实现两部分的组合使用。 例如 遥控器 &#xff08;抽象部分&#xff09;与 设备&#xff08;实现部分 电视&#xff0c;空调等&#xff09;。遥控器调用的是 设备方实现的接口。 设计模式&#xff0c;一定要敲代码理解 抽象模…

webpack-前置知识

前置知识-node的内置模块path path模块用于对路径和文件进行处理&#xff0c; 从路径中获取信息 dirname: 获取文件的父文件夹。 basename:获取文件名。 extname: 获取文件拓展名。 const path require("path")const fileName "C://test/a/b/c.txt"//.t…

租用阿里云的服务器多少钱?30元、61元、99元、165元、199元

租个阿里云的服务器多少钱&#xff1f;很便宜&#xff0c;云服务器2核2G3M固定带宽99元一年、2核4G服务器30元3个月、199元一年&#xff0c;轻量应用服务器2核2G3M配置61元一年、2核4G4M带宽165元一年&#xff0c;可以在阿里云CLUB中心查看 aliyun.club 当前最新的优惠券和活动…

专注项目管理的Mac工具 - Project Office Pro 最新版

Project Office Pro for Mac是一款功能强大的项目管理软件&#xff0c;旨在帮助用户更好地管理和跟踪项目进展&#xff0c;提高工作效率和质量。以下是该软件的主要功能介绍&#xff1a; 项目创建与编辑&#xff1a;用户可以根据自己的需求自定义项目计划&#xff0c;包括设置…

使用 Cloudflare 和全栈框架实现快速开发

去年 Cloudflare 发布了一系列新功能&#xff0c;使在 Cloudflare 上部署 Web 应用程序变得更加容易&#xff0c;我们看到 Astro、Next.js、Nuxt、Qwik、Remix、SolidStart、SvelteKit 和其他托管 Web 应用程序的大幅增长。 近日 Cloudflare 对这些 Web 框架的集成模块进行了重…

【Java网络编程】IP网络协议与TCP、UDP网络传输层协议

1.1、IP协议 当应用层的数据被封装后&#xff0c;想要将数据在网络上传输&#xff0c;数据究竟要被发往何处&#xff0c;又该如何精准的在网络上定位目标机器&#xff0c;此时起到关键作用的就是“IP协议”。IP协议的作用在于把各种数据包准确无误的传递给目标方&#xff0c;其…

LeetCode 378 有序矩阵中第K小的元素

题目信息 LeetoCode地址: . - 力扣&#xff08;LeetCode&#xff09; 题解内容大量转载于&#xff1a;. - 力扣&#xff08;LeetCode&#xff09; 题目理解 题意很直观&#xff0c;就是求二维矩阵中所有元素排序后第k小的数。 最小堆写法 该写法不再赘述&#xff0c;维护…

好看流光风格个人主页HTML源码

这是一款好看流光风格个人主页HTML源码&#xff0c;感觉挺喜欢的&#xff0c;需要的自行下载&#xff01; 源码下载 好看流光风格个人主页源码

“进击的巨人”:服务器硬件基础知识解析

引言&#xff1a; 服务器是网络环境中负责处理数据、运行应用程序和服务多用户的高性能计算机系统。了解服务器的硬件构成有助于更好地管理和优化IT资源。 服务器和普通PC的差异&#xff1a; 服务器具有比个人电脑更高的处理能力、稳定性和可靠性&#xff0c;它们通常运行在没…

【JavaEE】浅谈线程(一)

线程 前言线程的由来线程是什么线程的属性线程更高效的原因举个例子&#xff08;线程便利性的体现&#xff09; 多线程代码线程并发执行的代码jconsole(观测多线程) 线程的调度问题创建线程的几种方法1&#xff09;通过继承Thread 重写run2&#xff09;使用Runnable接口 重写ru…

.NET8 和 Vue.js 的前后端分离

在.NET 8中实现前后端分离主要涉及到两个部分&#xff1a;后端API的开发和前端应用的开发。后端API通常使用ASP.NET Core来构建&#xff0c;而前端应用则可以使用任何前端框架或技术栈&#xff0c;比如Vue.js、React或Angular等。下面是一个简化的步骤指南&#xff0c;帮助你在…

指针 基础知识

本笔记为观看56 指针-指针的定义和使用_哔哩哔哩_bilibili后的学习笔记 指针的定义和使用 1、定义指针 int main () {//1、定义指针int a 10;//指针定义的语法&#xff1a; 数据类型 * 指针变量名&#xff1b;int * p;//让指针记录变量a的地址p &a; //& 为取址符cou…

Mac资源库的东西可以删除吗?mac资源库在哪里打开 cleanmymacx是什么 cleanmymac免费下载

在使用Mac电脑的过程中&#xff0c;用户可能会遇到存储空间不足的问题。一种解决方法是清理不必要的文件&#xff0c;其中资源库&#xff08;Library&#xff09;文件夹是一个常被提及但又让人迷惑的目标。Mac资源库的东西可以删除吗&#xff1f;本文旨在解释Mac资源库的作用、…

Java常用函数接口

Java常用函数接口 Java 8 中引入的常用函数式接口&#xff0c;也就是 java.util.function 包中的接口。这些接口提供了一种简洁的方式来定义函数&#xff0c;常用于 Lambda 表达式和方法引用。下面是一些常用的接口&#xff1a; 一、Predicate&#xff08;断言&#xff09; …

应用性能分析工具CPU Profiler

简介 本文档介绍应用性能分析工具CPU Profiler的使用方法&#xff0c;该工具为开发者提供性能采样分析手段&#xff0c;可在不插桩情况下获取调用栈上各层函数的执行时间&#xff0c;并展示在时间轴上。 开发者可通过该工具查看TS/JS代码及NAPI代码执行过程中的时序及耗时情况…

c语言之动态内存管理及常见错误分析,柔性数组,内存划分

目录 前言 一&#xff1a;malloc,calloc,realloc,free四大函数 1.malloc 2.free 3.calloc 4.realloc 二&#xff1a;常见错误分析 1.malloc返回值不检查直接使用 2.对动态开辟空间的越界访问 3.对非动态开辟空间free 4.使用free释放动态开辟内存的一部分 5.对…

QAuth 2.0

OAuth 2.0授权框架支持第三方支持访问有限的HTTP服务&#xff0c;通过在资源所有者和HTTP服务之间进行一个批准交互来代表资源者去访问这些资源&#xff0c;或者通过允许第三方应用程序以自己的名义获取访问权限。 为了方便理解&#xff0c;可以想象OAuth2.0就是在用户资源和第…

多路转接-epoll/Reactor(2)

epoll 上次说到了poll&#xff0c;它存在效率问题&#xff0c;因此出现了改进的poll----epoll。 目前epoll是公认的效率最高的多路转接的方案。 快速了解epoll接口 epoll_create&#xff1a; 这个参数其实已经被废弃了。 这个值只要大于0就可以了。 这是用来创建一个epoll模…

用友U9 存在PatchFile.asmx接口任意文件上传漏洞

声明&#xff1a; 本文仅用于技术交流&#xff0c;请勿用于非法用途 由于传播、利用此文所提供的信息而造成的任何直接或者间接的后果及损失&#xff0c;均由使用者本人负责&#xff0c;文章作者不为此承担任何责任。 简介 用友U9是由中国用友软件股份有限公司开发的一款企业…