当前位置: 首页 > news >正文

设计模式之创建型模式---建造者模式

文章目录

  • 建造者模式概述
  • 经典的建造者模式
  • 建造者模式的变种
  • 总结

在这里插入图片描述

建造者模式概述

建造者模式是一种广泛使用的设计模式,在三方开源库和各种SDK中经常见到。建造者设计模式在四人帮的经典著作《设计模式:可复用面向对象软件基础》中被提及,它的定义为,将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。建造者模式目前主要有两种,一种是经典的建造者模式,另外一种是变种的建造者模式。本文就是介绍建造者模式的两种形态的Java实现

经典的建造者模式

我们学过Java都知道,当我们需要一个对象的时候,直接new一个就行了,我们new对象的时候需要给其传递一些属性,最后就能得到一个可以使用的对象啦,比如构建一个简单的车轮子对象,我们只需要new 车轮子(属性)就行,但是当我们要构造一个车的对象时就没那么简单了,因为一辆车的这个大对象又包含了车轮子,引擎,车身等小对象,这些对象需要我们单独new出了,然后再组合到一起,最终形成一辆车。这个过程如果还是使用我们程序员手动new就会很麻烦了,所以出现了经典的建造者模式。

经典的建造者模式主要有四个参与者:

  1. 复杂对象:复杂对象就是被构造的的对象,例如一辆车:Car,实现抽象建造者接口的时候会引用这个对象,然后定义其构造的过程
  2. 抽象建造者接口: 定义创建复杂对象的各个组成部件的操作,例如CarBuilder,定义构建车的各个组成部件的操作
  3. 抽象建造者接口的具体实现 :可以定义多个,这个实现是实际构建复杂对象的地方,在这个类中会提供一个方法返回构建的复杂对象
  4. 抽象建造者接口的构造者和使用者 : 在这里面调用对应的建造者接口方法构造组装得到复杂对象。

接下来,我们使用一个造车的简单例子介绍经典的建造者模式
首先我们需要确定要构造的复杂对象,这里的复杂对象就是我们要造的车,我们定义一个类表示要造的车。

public class Car {private String wheel;private String body;private String engine;private String color;private String name;public Car() {}public String getWheel() {return wheel;}public void setWheel(String wheel) {this.wheel = wheel;}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 getColor() {return color;}public void setColor(String color) {this.color = color;}public String getName() {return name;}public void setName(String name) {this.name = name;}@Overridepublic String toString() {return "Car{" +"wheel='" + wheel + '\'' +", body='" + body + '\'' +", engine='" + engine + '\'' +", color='" + color + '\'' +", name='" + name + '\'' +'}';}
}

接下来我们需要定义一个建造者接口,定义造车的各个操作,即定义抽象建造者接口。代码如下所示:

public interface CarBuilder {// 构建轮子void buildWheel();// 构建车身void buildBody();// 构建引擎void buildEngine();// 构建车身颜色void buildColor();// 构建名字void buildName();// 返回造好的车Car getCar();
}

定义好造车的操作后,我们就可以准备开始造车了,我们接下来分别定义造一辆奔驰和一辆宝马,这两种车的大致部件其实都差不多,无非都是轮子,车身,引擎,颜色,名字等,但是不同的就是各个部件中包含的技术,所以我们需要定义不同的类表示当前造的车,代码如下所示:
首先是宝马类:

public class BMWBuilder implements CarBuilder{private final Car mCar = new Car();@Overridepublic void buildWheel() {System.out.println("构建宝马的轮子");mCar.setWheel("宝马轮子");}@Overridepublic void buildBody() {System.out.println("构建宝马的车身");mCar.setBody("宝马车身");}@Overridepublic void buildEngine() {System.out.println("构建宝马的引擎");mCar.setEngine("宝马引擎");}@Overridepublic void buildColor() {System.out.println("构建宝马的颜色");mCar.setColor("黑色");}@Overridepublic void buildName() {System.out.println("构建宝马的名字");mCar.setName("宝马X5");}@Overridepublic Car getCar() {return mCar;}
}

奔驰车类:

public class BenzBuilder implements CarBuilder{private final Car mCar = new Car();@Overridepublic void buildWheel() {System.out.println("构建奔驰的轮子");mCar.setWheel("奔驰轮子");}@Overridepublic void buildBody() {System.out.println("构建奔驰的车身");mCar.setBody("奔驰车身");}@Overridepublic void buildEngine() {System.out.println("构建奔驰的引擎");mCar.setEngine("奔驰引擎");}@Overridepublic void buildColor() {System.out.println("构建奔驰的颜色");mCar.setColor("粉色");}@Overridepublic void buildName() {System.out.println("构建奔驰的名字");mCar.setName("奔驰");}@Overridepublic Car getCar() {return mCar;}
}

构造完上面的对象后,我们需要提供一个类来将这些构造的操作步骤组合到一起最终形成我们要构建的复杂对象,代码如下所示:

public class Director {private CarBuilder carBuilder;public Director(CarBuilder carBuilder){this.carBuilder = carBuilder;}public Car buildCar(){carBuilder.buildName();carBuilder.buildColor();carBuilder.buildWheel();carBuilder.buildBody();carBuilder.buildEngine();return carBuilder == null ? null : carBuilder.getCar();}
}

有了Director类,使用方只需要new一个Director对象,传入想要构建的车的Builder,调用buildCar方法就可以得到一个车的对象了。使用方法如下所示:

public class Client {public static void main(String[] args) {BMWBuilder bmwBuilder = new BMWBuilder();Director bmwDirector = new Director(bmwBuilder);Car bmwCar = bmwDirector.buildCar();System.out.println("构建了一辆宝马: " + bmwCar.toString());BenzBuilder benzBuilder = new BenzBuilder();Director benzDirector = new Director(benzBuilder);Car benzCar = benzDirector.buildCar();System.out.println("构建了一辆奔驰: " + benzCar.toString());}
}

运行结果:
在这里插入图片描述

建造者模式的变种

建造者模式的变种是目前用得比较多的,各大SDK初始化的时候基本都会使用建造者模式。经典的建造者模式重点在于抽象出对象创建的步骤,并通过调用不同的具体实现从而得到不同的结果。而变种的建造者模式目的在于减少对象在创建过程中引入的多个重载构造函数,可选参数以及Set方法的过度使用导致的不必要复杂性,变种的建造者模式更加适用于参数多的对象,并且这些参数中有部分参数是可选的,有部分参数是必传的。下面我们就以构建一个人(Person)的例子介绍变种的建造者模式。

public class Person {private final String mName; // 姓名,必填private final String mGender; // 性别,必填private final int mAge; // 年龄,可选private final String mPhoneNo; // 电话,可选private final String mWeight;// 体重,,可选public Person(String mName,String mGender,int mAge,String mPhoneNo,String mWeight) {this.mName = mName;this.mGender = mGender;this.mAge = mAge;this.mPhoneNo = mPhoneNo;this.mWeight = mWeight;}public Person(String mName,String mGender,int mAge,String mPhoneNo) {this(mName, mGender, mAge, mPhoneNo, "");}public Person(String mName,String mGender,int mAge) {this(mName, mGender, mAge, "", "");}
}

在上面的类中,我们的姓名和性别是必选项,其他是可选项,为了能够实现必选和可选的功能,我们需要在类中定义多个重载构造函数,来满足我们的需求,或者是给提供set和get方法,让必选项的参数通过构造函数传递,但是参数很多的时候就会很复杂了,传递参数的时候特别头痛。所以出现了变种的建造者模式。代码如下:

public class PersonB {private final String mName; // 姓名private final String mGender; // 性别private final int mAge; // 年龄private final String mPhoneNo; // 电话private final String mWeight;// 体重private PersonB(PersonBuilder builder){mName = builder.name;mGender = builder.gender;mAge = builder.age;mPhoneNo = builder.phoneNo;mWeight = builder.weight;}public String getName() {return mName;}public String getGender() {return mGender;}public int getAge() {return mAge;}public String getPhoneNo() {return mPhoneNo;}public String getWeight() {return mWeight;}@Overridepublic String toString() {return "PersonB{" +"mName='" + mName + '\'' +", mGender='" + mGender + '\'' +", mAge=" + mAge +", mPhoneNo='" + mPhoneNo + '\'' +", mWeight='" + mWeight + '\'' +'}';}public static class PersonBuilder {private final String name; // 姓名private final String gender; // 性别private int age; // 年龄private  String phoneNo; // 电话private String weight;// 体重public PersonBuilder(String name,String gender){this.name = name;this.gender = gender;}public PersonBuilder age(int age){this.age = age;return this;}public PersonBuilder phone(String phoneNo){this.phoneNo = phoneNo;return this;}public PersonBuilder weight(String weight){this.weight = weight;return this;}public PersonB build(){return new PersonB(this);}}
}

观察上面的类我们可以发现,首先我们需要构造的对象PersonB的构造函数是私有的,意味着调用者无法直接通过实例化获取PersonB 的对象,其次PersonB类里面的属性是final的并且在构造函数中设置,对外只提供get方法,即调用者只能用,不能改。最后通过PersonBuilder的构造函数接收必选参数,其他的属性可以通过PersonBuilder提供的方法设置,其中每个方法都会返回当前的PersonBuilder对象,这样可以让我们设置参数的时候使用链式调用,如下所示:

  public PersonBuilder age(int age){this.age = age;return this;}

最后,我们可以看下如何使用变种的建造者模式:

public class Client {public static void main(String[] args) {// 构建一个PersonPersonB personB =  new PersonB.PersonBuilder("职场007","male").age(28).phone("1234567890").weight("83kg").build();System.out.println("构建者模式构建出的对象: " + personB);}
}

运行结果:
在这里插入图片描述

总结

以上就是建造者模式的内容,本文分别介绍了两种形式的建造者模式以及Java的实现,其中用得最多的就是变种的建造者模式,建造者模式其实有个缺点就是需要编写很多的样板代码,但是我认为尽管这样还是不影响建造者模式的优雅,并且在Android Studio也有自动化生成变种建造者模式的插件,但是我不建议使用,除非读者已经对建造者模式很了解了。不然还是得仔细的看下建造者模式的设计思想,这样在看优秀库的源码时才会感觉到事半功倍。

相关文章:

设计模式之创建型模式---建造者模式

文章目录 建造者模式概述经典的建造者模式建造者模式的变种总结 建造者模式概述 建造者模式是一种广泛使用的设计模式,在三方开源库和各种SDK中经常见到。建造者设计模式在四人帮的经典著作《设计模式:可复用面向对象软件基础》中被提及,它的…...

如何从零开始训练一个语言模型

如何从零开始训练一个语言模型 #mermaid-svg-gtUlIrFtNPw1oV5a {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-gtUlIrFtNPw1oV5a .error-icon{fill:#552222;}#mermaid-svg-gtUlIrFtNPw1oV5a .error-text{fill:#5522…...

Python 设计一个监督自己的软件1

基本要求:每做一件事,软件就会按照事情权重加相应的分数,总分数也会增加,要可视化页面 使用Python编写的一个简单的日常任务记录和评分系统,包括可视化页面。 首先,我们定义一个任务字典,其中包含各种日常任务及其对应的权重分数…...

商家转账到零钱权限开通操作攻略

商家转账到零钱是什么? 商家转账到零钱是微信商户号里的一个功能,很早以前叫企业付款到零钱。 从2022年5月18日,原“企业付款到零钱”升级为“商家转账到零钱”,已开通商户的功能使用暂不受影响,新开通商户可前往「产…...

【DAC‘ 2022】Kite: A Family of Heterogeneous Interposer Topologies

Kite: A Family of Heterogeneous Interposer Topologies Enabled via Accurate Interconnect Modeling 背景和动机 背景动机 工作内容 KITE 拓扑 实验方法和评估结果 Kite: A Family of Heterogeneous Interposer Topologies Enabled via Accurate Interconnect Modeling 通…...

数据结构—堆

什么是堆 堆是一种特殊的树形结构,其中每个节点都有一个值。堆可以分为两种类型:最大堆和最小堆。在最大堆中,每个节点的值都大于等于其子节点的值;而在最小堆中,每个节点的值都小于等于其子节点的值。这种特性使得堆…...

Kubernetes学习笔记8

Kubernetes集群客户端工具kubectl 我们已经能够部署Kubernetes了,那么我们如何使用Kubernetes集群运行企业的应用程序呢?那么,我们就需要使用命令行工具kubectl。 kubectl就是控制Kubernetes的驾驶舱,它允许你执行所有可能的Kube…...

[渗透利器]在线渗透测试工具箱?测评

前言 hxd更新完了在线工具箱,受邀写一下使用体验以及测评 使用体验 这个工具箱设计的比较轻便,以往用过的工具箱大多都是以离线打包的方式发布,该工具箱,作者自己掏钱自己买服务器,自己买带宽,先生大义。…...

rocketmq和rabbitmq总是分不清?

1. 官方解答 摘自百度搜索: 2. 通俗易懂的回答...

利用Python ARM网关仓储物流AGV小车控制器

在现代智慧物流体系中,高效的信息管理系统是物流中心实现精准跟踪货物、科学管理库存及优化配送路线的关键环节。通过采用ARM架构的工控机或网关,并结合Python的二次开发能力,可以有效集成并强化物流管理系统的数据处理与通信功能&#xff0c…...

Transformer详解和知识点总结

目录 1. 注意力机制1.1 注意力评分函数1.2 多头注意力(Multi-head self-attention) 2. Layer norm3. 模型结构4. Attention在Transformer中三种形式的应用 论文:https://arxiv.org/abs/1706.03762 李沐B站视频:https://www.bilibi…...

【Ubuntu】update-alternatives 命令详解

1、查看所有候选项 ​​​​​​​sudo update-alternatives --list java 2、​​​​​​​更换候选项 sudo update-alternatives --config java 3、自动选择优先级最高的作为默认项 sudo update-alternatives --auto java 4、删除候选项 sudo update-alternatives --rem…...

数据结构之堆练习题及PriorityQueue深入讲解!

题外话 上午学了一些JavaEE初阶知识,下午继续复习数据结构内容 正题 本篇内容把堆的练习题做一下 第一题 1.下列关键字序列为堆的是:( A ) A: 100,60,70,50,32,65 B: 60,70,65,50,32,100 C: 65,100,70,32,50,60 D: 70,65,100,32,50,60 E: 32,50,100,70,65,60 …...

MySQL——Linux安装包

一、下载安装包 MySQL下载路径: MySQL :: MySQL Downloads //默认下载的企业版MySQL 下载社区版MySQL MySQL :: MySQL Community Downloads 1、源码下载 2、仓库配置 3、二进制安装包 基于官方仓库安装 清华centos 软件仓库: Index of /cen…...

MySQL学习笔记(数据类型, DDL, DML, DQL, DCL)

Learning note 1、前言2、数据类型2.1、数值类型2.2、字符串类型2.3、日期类型 3、DDL总览数据库/表切换数据库查看表内容创建数据库/表删除数据库/表添加字段删除字段表的重命名修改字段名(以及对应的数据类型) 4、DML往字段里写入具体内容修改字段内容…...

Asible管理变量与事实——管理变量(1)

Ansible简介 Ansible支持利用变量来储存值,并在Ansible项目的所有文件中重复使用这些值。这可以简化项目的创建和维护,并减少错误的数量。 通过变量,您可以轻松地在Ansible项目中管理给定环境的动态值。例如,变量可能包含下面这些…...

【微服务】------微服务架构技术栈

目前微服务早已火遍大江南北,对于开发来说,我们时刻关注着技术的迭代更新,而项目采用什么技术栈选型落地是开发、产品都需要关注的事情,该篇博客主要分享一些目前普遍公司都在用的技术栈,快来分享一下你当前所在用的技…...

【SCI绘图】【小提琴系列1 python】绘制按分类变量分组的垂直小提琴图

SCI,CCF,EI及核心期刊绘图宝典,爆款持续更新,助力科研! 本期分享: 【SCI绘图】【小提琴系列1 python】绘制按分类变量分组的垂直小提琴图,文末附完整代码 小提琴图是一种常用的数据可视化工具…...

docker------docker入门

🎈个人主页:靓仔很忙i 💻B 站主页:👉B站👈 🎉欢迎 👍点赞✍评论⭐收藏 🤗收录专栏:Linux 🤝希望本文对您有所裨益,如有不足之处&#…...

终极数据传输隐秘通道

SOCKS5代理作为网络请求中介的高级形态,提供了一种方法,通过它,数据包在传达其最终目的地前,首先经过一个第三方服务器。这种代理的先进之处在于其对各种协议的支持,包括HTTP、FTP和SMTP,以及它的认证机制&…...

Qt中的事件与事件处理

Qt框架中的事件处理机制是其GUI编程的核心部分,它确保了用户与应用程序之间的交互能够得到正确的响应。以下是对Qt事件处理机制的详细讲解以及提供一些基本示例。 1. 事件与事件处理简介 事件:在Qt中,所有的事件都是从QEvent基类派生出来的&…...

中间件漏洞攻防学习总结

前言 面试常问的一些中间件,学习总结一下。以下环境分别使用vulhub和vulfocus复现。 Apache apache 文件上传 (CVE-2017-15715) 描述: Apache(音译为阿帕奇)是世界使用排名第一的Web服务器软件。它可以运行在几乎所有广泛使用的计算机平台上,由于其跨…...

HarmonyOS开发实例:【分布式数据管理】

介绍 本示例展示了在eTS中分布式数据管理的使用,包括KVManager对象实例的创建和KVStore数据流转的使用。 通过设备管理接口[ohos.distributedDeviceManager],实现设备之间的kvStore对象的数据传输交互,该对象拥有以下能力 ; 1、注册和解除注…...

蓝桥杯——运动会

题目 n 个运动员参加一个由 m 项运动组成的运动会,要求每个运动员参加每个项目。每个运动员在每个项目都有一个成绩,成绩越大排名越靠前。每个项目,不同运功员的成绩不会相 同,因此排名不会相同。(但是不同项目可能成绩会相同) 每…...

如何搭建APP分发平台分发平台搭建教程

搭建一个APP分发平台可以帮助开发者更好地分发和管理他们的应用程序。下面是一个简要的教程,介绍如何搭建一个APP分发平台。 1.确定需求和功能:首先,确定你的APP分发平台的需求和功能。考虑以下几个方面: 用户注册和登录&#xff…...

【计算机专业必看】详细说明文件打开模式r,w,a,r+,w+,a+的区别和联系

文章目录 1、联系2、区别r(只读)w(只写)a(追加)r(读写,文件必须存在)w(读写,文件不存在则创建,存在则清空)a(读…...

Db2数据库稳定性解决方案

常见的数据库查询或写入慢,一般有以下情况 1、数据库经常有删除或有大量查询,(导致磁盘碎裂,数据库缓存堆积) 2、数据量大,导致在查询或写入时,由于负载高,导致系统慢 3、业务代码…...

如何用Python编写简单的网络爬虫(页面代码简单分析过程)

一、什么是网络爬虫 在当今信息爆炸的时代,网络上蕴藏着大量宝贵的信息,如何高效地从中获取所需信息成为了一个重要课题。网络爬虫(Web crawler)作为一种自动化工具,可以帮助我们实现这一目标,用于数据分析…...

【随笔】Git 高级篇 -- 最近标签距离查询 git describe(二十一)

💌 所属专栏:【Git】 😀 作  者:我是夜阑的狗🐶 🚀 个人简介:一个正在努力学技术的CV工程师,专注基础和实战分享 ,欢迎咨询! 💖 欢迎大…...

【leetcode面试经典150题】7.买卖股票的最佳时机(C++)

【leetcode面试经典150题】专栏系列将为准备暑期实习生以及秋招的同学们提高在面试时的经典面试算法题的思路和想法。本专栏将以一题多解和精简算法思路为主,题解使用C语言。(若有使用其他语言的同学也可了解题解思路,本质上语法内容一致&…...