建造者模式深入理解:演示建造单个和多个产品的实践,结合模板模式;支持并行构建,通俗易懂

首先呢看下建造者的定义是什么样的,先读一遍

建造者模式

建造者模式(Builder Pattern)是一种创建型设计模式,它主要用于将一个复杂对象的构建过程与它的表示分离,使得同样的构建过程可以创建不同的表现形式。这种模式通过一系列可重用的独立的类(称为建造者或构建器)来一步一步创建一个复杂的对象,而不需要知道具体的内部构造细节

优缺点

建造者模式的主要优点

  1. 封装性好:通过建造者将产品的各个部件和组装过程封装起来,客户端无需了解产品内部的具体构造细节,只需指定需要的产品类型和配置即可。
  2. 扩展性好:由于每个具体建造者都是相互独立的,因此新增一种产品或者变更已有产品的构建方式时,只需要新增或修改相应的建造者类,不影响其他部分代码,从而实现系统的松耦合。
  3. 便于控制构建过程:在构建过程中,可以根据需要逐步细化构造步骤,灵活地控制产品的创建过程,甚至支持动态决定构建部件的数量和顺序。
  4. 便于并行构造:在某些场景下,不同部分的构建可以独立进行,有利于提高系统性能,特别是在多线程环境下的构建。

建造者模式的主要缺点

  1. 增加类的数量:引入建造者模式会增加额外的类,包括抽象建造者、具体建造者和可能的导演类等,增加了系统的复杂性和理解难度。
  2. 内部修改困难:一旦产品结构较为复杂,对于产品内部细节的改动可能会导致多个建造者的相关逻辑都需要调整,维护成本相对较高。
  3. 过度设计风险:如果对象结构比较简单,或者变化不多,使用建造者模式可能会显得过于复杂,不适用于简单对象的构建。
    总结来说,建造者模式非常适合用于创建具有多重构造参数或组合选项的复杂对象,尤其当这些选项的不同组合可能导致大量微小差异的产品实例时,该模式能够很好地管理和组织这些复杂性。

网图来一张
在这里插入图片描述
好了,直接上代码,这里我们先构建一个CarProduct,很多描述都写在了对应的注释中了啊,这里就不过多赘述

package com.mtgg.laoxiang.service.example.designer.builder;import lombok.Data;/*** 要构建的产品对象*/
@Data
public class CarProduct {private String partA;private String partB;private String partC;
}
package com.mtgg.laoxiang.service.example.designer.builder;/*** 建造者抽象类*/
public abstract class Builder {//建造产品时,实例化,相当于统一放到一个地方,product相当于一个封装,里面可以放各种东西的组成protected CarProduct carProduct = new CarProduct();//建造,建造各种东西然后set到product中public abstract void builderPartA();public abstract void builderPartB();public abstract void builderPartC();//提供获得产品的入口,要获得这个产品,就调用这个方法public CarProduct getResult() {return carProduct;}}

上面定义了产品,构造器,获取产品的方法,下面这个就是构造器要具体干的活了

package com.mtgg.laoxiang.service.example.designer.builder;public class BJBuilder extends Builder{@Overridepublic void builderPartA() {System.out.println("构建个1球");carProduct.setPartA("1球");}@Overridepublic void builderPartB() {System.out.println("构建个2球");carProduct.setPartB("2球");}@Overridepublic void builderPartC() {System.out.println("构建个3球");carProduct.setPartC("3球");}
}
package com.mtgg.laoxiang.service.example.designer.builder;public class HZBuilder extends Builder{@Overridepublic void builderPartA() {System.out.println("构建个1香蕉");carProduct.setPartA("1香蕉");}@Overridepublic void builderPartB() {System.out.println("构建个2香蕉");carProduct.setPartB("2香蕉");}@Overridepublic void builderPartC() {System.out.println("构建个3香蕉");carProduct.setPartC("3香蕉");}
}

指挥者来了,指挥我到底想要啥,什么数量,什么顺序,定义几个图纸来交给构造器去构造,然后main使用的时候直接调用这个定义好的流程,就能拿到对应的产品

package com.mtgg.laoxiang.service.example.designer.builder;/*** 指挥者* 控制生成流程*/
public class Director {//这个抽象类可以定义成全局变量,也可以定义接口,此处可以引用接口,更不违反原则private Builder builder;/*** 注入builder*/private Director(Builder builder) {this.builder = builder;}/*** 控制流程,此处类似使用模板模式*/public CarProduct construct2(){builder.builderPartC();builder.builderPartA();return builder.getResult();}public CarProduct construct(){builder.builderPartB();builder.builderPartA();builder.builderPartC();return builder.getResult();}public static void main(String[] args) {//此处可选择不同的建造者建造产品Director director = new Director(new HZBuilder());CarProduct construct = director.construct();System.out.println(construct);director = new Director(new BJBuilder());CarProduct construct1 = director.construct2();System.out.println(construct1);}}

*构建个2香蕉
构建个1香蕉
构建个3香蕉
Product(partA=1香蕉, partB=2香蕉, partC=3香蕉)
构建个3球
构建个1球
Product(partA=1球, partB=null, partC=3球) *

在这里插入图片描述

如果我想建造另外一个对象呢?难道类似的类都要加一份?那肯定是low的,做法如下,

可以加具体建造,定义好要建造的东西,再建一个指挥者方法,尽量不要在原来的方法上改,改造后如下

假如有另一个对象PhoneProduct

@Data
public class PhoneProduct {private String pa;private String pb;private String pc;
}

Builder中加上要构建的这个产品,并加个返回产品的方法,所以这么看的话那几个构建的抽象方法就不能太个性化,最好抽象一些,像是定义三四个工厂一样,具体怎么生产看子类实现

public abstract class Builder {//建造产品时,实例化,相当于统一放到一个地方,product相当于一个封装,里面可以放各种东西的组成//另外一个产品protected PhoneProduct phoneProduct = new PhoneProduct();
……………………public PhoneProduct getPhoneResult() {return phoneProduct;}
}

好了我们定义一个子类去构建具体的内容,不用改另外一个对象的构建,保证对扩展开放,对修改关闭

public class XMBuilder extends Builder{@Overridepublic void builderPartA() {System.out.println("小米a");phoneProduct.setPa("pa");}@Overridepublic void builderPartB() {System.out.println("小米b");phoneProduct.setPb("pb");}@Overridepublic void builderPartC() {System.out.println("小米c");phoneProduct.setPc("pc");}
}

指挥者我们改造一下,构建顺序以及数量都可以抽出来共用,只需要定义construct2或constructPhone方法,指定模板,返回产品就OK了,想要啥产品要啥产品

public class Director {//这个抽象类可以定义成全局变量,也可以定义接口,此处可以引用接口,更不违反原则private Builder builder;/*** 注入builder*/private Director(Builder builder) {this.builder = builder;}/*** 构建模板 定义构建顺序以及内容*/public void buildTemplateA(){builder.builderPartB();builder.builderPartA();builder.builderPartC();}/*** 构建模板 定义构建顺序以及内容*/public void buildTemplateB(){builder.builderPartC();builder.builderPartA();}/*** 构建以及获取car产品的入口*/public CarProduct construct2(){this.buildTemplateB();return builder.getResult();}//不同形态的car产品public CarProduct construct(){this.buildTemplateA();return builder.getResult();}//这个是构建和获取phone产品的入口public PhoneProduct constructPhone(){this.buildTemplateA();return builder.getPhoneResult();}public static void main(String[] args) {//此处可选择不同的建造者建造产品Director director = new Director(new HZBuilder());CarProduct construct = director.construct();System.out.println(construct);director = new Director(new BJBuilder());CarProduct construct1 = director.construct2();System.out.println(construct1);//构建另外一个产品,使用时指定用XMBuilder这个厂家生产的就行director = new Director(new XMBuilder());PhoneProduct construct2 = director.constructPhone();System.out.println(construct2);}}

下面这是执行结果

构建个2香蕉
构建个1香蕉
构建个3香蕉
CarProduct(partA=1香蕉, partB=2香蕉, partC=3香蕉)
构建个3球
构建个1球
CarProduct(partA=1球, partB=null, partC=3球)
小米b
小米a
小米c
PhoneProduct(pa=pa, pb=pb, pc=pc)

并行构建我还没事件完毕,对不起大家,后面我补上,主要思路就是用CyclicBarrier,大家可以先试一下

在这里插入图片描述

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

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

相关文章

微软Office 2019 批量授权版

软件介绍 微软办公软件套件Microsoft Office 2019 专业增强版2024年1月批量许可版更新推送!Office2019正式版2018年10月份推出,主要为多人跨平台办公与团队协作打造。Office2019整合对过去三年在Office365里所有功能,包括对Word、Excel、Pow…

【PyQt小知识 - 7】:QLineEdit设置输入的文本以圆点或星号等方式显示

文章目录 setEchoMode setEchoMode 在PyQt中,QLineEdit是一种用于接收用户输入的小部件(widget)。setEchoMode是QLineEdit类中的一个方法,可以用于设置文本输入框中的文本显示模式。它接受一个参数来指定要使用的模式。 setEcho…

GEE查看MODIS的NDVI、EVI产品并生成逐日/逐月NDVI曲线

目录 MOD13Q1MOD09GA计算逐日/逐月NDVI生成曲线参考博文 MOD13Q1 MOD13Q1有两个产品:NDVI和EVI,每16天为全球提供,分辨率为250M 通过查看时间,该NDVI产品是16天一景 MOD09GA 提供逐日的表面反射率产品,分辨率为500m…

09Bean的生命周期/作用域不同管理方式不同/自己new的对象纳入Spring容器管理

Spring其实就是一个管理Bean对象的工厂。它负责对象的创建,对象的销毁等。 所谓的生命周期就是:对象从创建开始到最终销毁的整个过程。 Bean的生命周期之5步 ● 第一步:实例化Bean(无参构造方法执行) ● 第二步:Bean属性赋值(注…

一文搞懂MongoDB

简介 什么是MongoDB MongoDB是一个基于分布式文件存储的NoSQL数据库,基于C语言开发而成的。它以文档存储格式(BSON)为基础,是由字段和值对组成的数据结构。 扩展: BSON(Binary JSON)是一种二进…

力扣日记1.11-【二叉树篇】450. 删除二叉搜索树中的节点

力扣日记:【二叉树篇】450. 删除二叉搜索树中的节点 日期:2024.1.11 参考:代码随想录、力扣 450. 删除二叉搜索树中的节点 题目描述 难度:中等 给定一个二叉搜索树的根节点 root 和一个值 key,删除二叉搜索树中的 key…

区间预测 | Matlab实现CNN-BiLSTM-KDE的卷积双向长短期神经网络结合核密度估计多变量时序区间预测

区间预测 | Matlab实现CNN-BiLSTM-KDE的卷积双向长短期神经网络结合核密度估计多变量时序区间预测 目录 区间预测 | Matlab实现CNN-BiLSTM-KDE的卷积双向长短期神经网络结合核密度估计多变量时序区间预测效果一览基本介绍程序设计参考资料 效果一览 基本介绍 1.CNN-BiLSTM-KDE多…

机器学习原理到Python代码实现之KNN【K近邻】

K-Nearest Neighbor K近邻算法 该文章作为机器学习的第三篇文章,主要介绍的是K紧邻算法,这是机器学习中最简单的一种分类算法,也是机器学习中最基础的一种算法。 难度系数:⭐ 更多相关工作请参考:Github 算法介绍 K近…

【python】python新年烟花代码【附源码】

欢迎来到英杰社区https://bbs.csdn.net/topics/617804998 新年的钟声即将敲响,为了庆祝这个喜庆的时刻,我们可以用 Python 编写一个炫彩夺目的烟花盛典。本文将详细介绍如何使用 Pygame 库创建一个令人惊叹的烟花效果。 一、效果图: 二…

安防视频监控系统EasyCVR设备分组中在线/离线数量统计的开发与实现

安防视频监控EasyCVR系统具备较强的兼容性,它可以支持国标GB28181、RTSP/Onvif、RTMP,以及厂家的私有协议与SDK,如:海康ehome、海康sdk、大华sdk、宇视sdk、华为sdk、萤石云sdk、乐橙sdk等。EasyCVR平台可覆盖多类型的设备接入&am…

旋转图像(Rotate Image)- LeetCode 48

旋转图像(Rotate Image)- LeetCode 48 题目描述 给定一个n x n 2D矩阵表示的图像,我们需要将该图像旋转90度。并且,重要的是我们需要在原地修改这个2D矩阵,不能使用额外的2D矩阵。 解题思路 1. 转置操作 首先&…

R语言下载安装及VScode配置

文章目录 1. R 下载和安装1.1 下载1.2 安装 2. VSCODE 配置2.1 安装R拓展2.2 安装R语言辅助功能包2.3 DEBUG 1. R 下载和安装 1.1 下载 网址:https://www.r-project.org/ 选择一个镜像地址下载 选择对应的版本 一般选择base即可 1.2 安装 下载安装包后按提示安装…

Npm+BootStrap布局

NpmBootStrap布局 NodeJs NodeJs概述 Node.js是Ryan Dahl于2009年5月基于Chrome V8引擎构建的一个开源和跨平台的JavaScript运行环境。主要在Windows、Linux、Unix、MacOSX等不同平台上运行 NodeJs意义 Node.js是一个javascript运行环境,它使得javascript可以脱离…

jupyter notebook 配置conda 虚拟环境python

conda创建python环境 conda create -n openvoice python3.9 激活环境 source activate openvoice 在虚拟环境中安装ipykernel pip install ipykernel 添加虚拟环境进到 jupyter notebook python -m ipykernel install --user --name openvoice --display-name openvoice …

Springboot+vue的毕业论文管理系统(有报告)。Javaee项目,springboot vue前后端分离项目

演示视频: Springbootvue的毕业论文管理系统(有报告)。Javaee项目,springboot vue前后端分离项目 项目介绍: 本文设计了一个基于Springbootvue的前后端分离的毕业论文管理系统,采用M(model&…

QT延时五种实现方法

QT中没有提供专用延时函数,但有多种实现方法,各有特点,如下所示: 一.阻塞方式 1.多线程程序使用QThread::sleep()或者QThread::msleep()或QThread::usleep()或QThread::wait()进行延时处理。 Sleep不会释放对象锁,其…

第3章:python的判断语句

学一门语言,无外乎多敲,多用,记得回顾昨天写过的代码呀 布尔类型和比较运算符 布尔类型的定义 使用比较运算符进行比较运算得到布尔类型的结果 比较运算符 """ 演示布尔类型的定义 以及比较运算符的应用 ​ """…

并发前置知识一:线程基础

一、通用的线程生命周期:“五态模型” 二、java线程有哪几种状态? New:创建完线程Runable:start(),这里的Runnable包含操作的系统的Running(运行状态)和Ready(上面的可运行状态)Blo…

vscode配置Todo Tree插件

一、在VSCode中安装插件Todo Tree ​​​​ 二、按下快捷键ctrlshiftP,输入setting.jspn 选择相应的配置范围,我们选择的是用户配置 Open User Settings(JSON),将以下代码插入其中。 {//todo-tree 标签配置从这里开始 标签兼容大小写字母(…

强化学习9——免模型预测算法介绍(蒙特卡洛方法和时步差分方法)

对于大部分情况来说,环境是未知的,也就是说状态转移概率未知,对于这种情况的算法称为免模型预测算法。免模型算法与环境不断交互学习,但是需要大量的运算。 蒙特卡洛方法 蒙特卡罗方法通过重复随机抽选,之后运用统计…