设计模式--建造者模式详解

建造者模式

  • 建造者模式也属于创建型模式,它提供了一种创建对象的最佳方式

  • 定义:将一个复杂对象的构建和它的表示分离,使得同样的构建过程可以创建不同的表示(假设有不同的建造者实现类,可以产生不同的产品)

  • 主要作用:在用户不知道对象的创建过程和细节的情况下(用户只需要调指挥者来创建就可以了)就可以直接创建复杂的对象

  • 用户只需要给出指定复杂对象的类型和内容,建造者负责按顺序创建复杂对象(把内部的建造过程和细节隐藏起来)

  • 例子:

    • 工厂(建造者模式):负责制造汽车(组装过程和细节在工厂内)

    • 汽车购买者(用户):你只要说出你需要的型号(对象的类型与内容),然后可以直接购买就可以使用了(虽然不知道汽车怎么组装的(车轮、车门、发动机、方向盘等等))

  • 角色分析:

  • 既然是建造者模式,那么我们还是继续就以造房子为例子,假设将造房简化为以下步骤:

    • 地基

    • 钢筋工程

    • 铺电线

    • 粉刷

如果要盖一间房子,首先是要一个建筑公司或工程承包商(指挥者),承包商指挥工人(具体建造者)来造房子(产品),最后验收

代码展示:

首先先创建抽象建造者

package com.lyc.builder.demo01;
//抽象的建造者,只负责定义一些接口与方法
public abstract class Builder {public abstract void buildPartA();public abstract void buildPartB();public abstract void buildPartC();public abstract void buildPartD();//完工:得到产品public abstract Product getResult();
}

再创建产品类

package com.lyc.builder.demo01;import lombok.Data;//产品:房子
@Data
public class Product {private String partA;private String partB;private String partC;private String partD;
}

再创建具体建造者实现类

package com.lyc.builder.demo01;
//具体的建造者 worker是builder的具体实现,一个builder可能有几个不同的worker
public class Worker extends Builder{private Product product;public Worker(){product = new Product();}@Overridepublic void buildPartA() {product.setPartA("partA");System.out.println("partA");}@Overridepublic void buildPartB() {product.setPartB("partB");System.out.println("partB");}@Overridepublic void buildPartC() {product.setPartC("partC");System.out.println("partC");}@Overridepublic void buildPartD() {product.setPartD("partD");System.out.println("partD");}@Overridepublic Product getResult() {return product;}
}

在创建指挥类Director

package com.lyc.builder.demo01;
//指挥者 核心,负责指挥构建一个工程,工程如何构建,有他决定
public class Director {//指挥工人按照顺序建造房子public Product builder(Builder builder){//指挥者可以指挥工人按照不同的顺序执行方法,builder.buildPartA();builder.buildPartB();builder.buildPartC();builder.buildPartD();//返回产品return builder.getResult();}
}

最后进行测试

public class Test {public static void main(String[] args) {//指挥Director director = new Director();Product builder = director.builder(new Worker());System.out.println(builder.toString());}
}

细节分析:

  • 上面示例是Builder模式的常规用法,导演Director在Builder模式中具有重要的作用,它用于指导具体构建者如何构建产品控制调用先后次序并向调用者返回完整的产品类,但是有些情况下需要简化系统结构,可以把Director与抽象建造者进行结合

  • 通过静态内部类方式实现零件无序装配构造,这种方式使用更加灵活,更符合定义,内部有复杂对象的默认实现,使用时可以根据用户需求自由定义更改内容,并且无需改变具体的构造方式。就可以生产出不同复杂的产品

  • 比如:汉堡套餐,服务员(具体建造者)可以随意搭配任意几种产品组成一款套餐(产品),比第一种少了Director,主要是因为第二种方式把指挥者交给用户操作,使得产品创建更加简单灵活

第二种方式代码展示:

首先还是需要创建抽象建造类

public abstract class Builder {public abstract Builder buildPartA(String msg); //汉堡public abstract Builder buildPartB(String msg); //可乐public abstract Builder buildPartC(String msg); //薯条public abstract Builder buildPartD(String msg); //甜品// 返回产品public abstract Product getResult();
}

创建产品类(这里存放着默认的产品)

import lombok.Data;//产品:套餐
@Data
public class Product {//默认套餐private String partA = "汉堡";private String partB = "可乐";private String partC = "薯条";private String partD = "甜点";
}

具体的创建者实现类

package com.lyc.builder.demo02;
//具体建造者
public class Worker extends Builder{private Product product;public Worker(){product = new Product();}@Overridepublic Builder buildPartA(String msg) {product.setPartA(msg);return this;}@Overridepublic Builder buildPartB(String msg) {product.setPartB(msg);return this;}@Overridepublic Builder buildPartC(String msg) {product.setPartC(msg);return this;}@Overridepublic Builder buildPartD(String msg) {product.setPartD(msg);return this;}@Overridepublic Product getResult() {return product;}
}

最后进行测试

package com.lyc.builder.demo02;public class Test {public static void main(String[] args) {//服务员Worker worker = new Worker();//链式编程 :在原来的基础上,可以自由组合,如果不组合,也有默认的套餐Product result = worker.buildPartA("全家桶").buildPartB("雪碧").getResult();System.out.println(result.toString());}
}

这里将指挥者与客户端相结合,让客户端自己来进行套餐的搭配。

建造者模式与工厂模式的区别:

工厂模式是造什么,建造者模式是怎么造,一个宏观,一个微观

建造者模式优点:

  • 产品的建造与表示分离,实现了解耦,使用建造者模式可以使客户端不必知道产品内部组成的细节。

  • 将复杂的产品的创建步骤分解在不同的方法中,使得创建过程更加清晰

  • 具体的建造者类之间是相互独立的,这有利于系统的扩展,增加新的具体建造者无需修改原有类库的代码,符合“开闭原则”。

缺点:

  • 建造者模式所创建的产品一般具有较多的共同点,其组成部分相似;如果产品之间的差异性很大,则不适合使用创造者模式,因此其适用范围受到了一定的限制。

  • 如果产品的内部变化复杂,可能会导致需要定义很多具体建造者来实现这种变化,导致系统变得很庞大

应用场景:

  • 需要生成的产品对象有复杂的内部结构,这些产品对象具备共性;

  • 隔离复杂对象的创建和使用,并使得相同的创建过程可以创建不同的产品。

  • 适合于一个具有较多的零件(属性)的产品(对象)的创建过程。

建造者与抽象工厂模式的比较:

  • 与抽象工厂模式相比,建造者模式返回一个组装好的完整产品,而抽象工厂模式返回一系列相关的产品,这些产品位于不同的产品等级结构,构成了一个产品族

  • 在抽象工厂模式中,客户端实例化工厂类,然后调用工厂方法获取所需产品对象,抽象工厂模式侧重于直接通过工厂制造获得对象 而在建造者模式中客户端可以不直接调用建造者的相关方法,而是通过指挥者类来指导如何生成对象,包括对象的组装过程和建造步骤,它侧重于一步步构造一个复杂对象,返回一个完整的对象。

  • 如果将抽象工厂模式看成汽车配件生产工厂,生产一个产品族的产品,那么建造者模式就是一个汽车组装工厂,通过对部件的组装可以返回一辆完整的汽车!

我们需要清楚的认识到工厂模式与创建者模式的区别,并且勤加练习,希望对大家有所帮助

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

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

相关文章

PCB 过孔铜厚的深入指南

***前言:在上一期的文章中介绍了PCB制造的工艺流程,但仍然想在过孔的铜厚和PCB的过孔厚径比两个方面再深入介绍。 PCB铜厚的定义 电路中铜的厚度以盎司(oz)**表示。那么,为什么用重量单位来表示厚度呢? 盎司(oz)的定义 将1盎司(28.35 克)的铜…

如何配置 Conda 使用镜像源加速

如何配置 Conda 使用镜像源加速 为了提高使用 Anaconda 或 Miniconda 时包管理的速度,特别是在国内网络环境下,可以通过配置镜像源来实现更快的下载。以下是详细的步骤说明: 1. 安装 Conda(如果尚未安装) 如果你还没…

【k8s】k8s是怎么实现自动扩缩的

Kubernetes 提供了多种自动扩缩容机制,主要包括 Pod 水平自动扩缩(HPA)、垂直 Pod 自动扩缩(VPA) 和 集群自动扩缩(Cluster Autoscaler)。以下是它们的实现原理和配置方法: 1. Pod …

Reflex 完全指南:用 Python 构建现代 Web 应用的终极体验

“写 Python,就能构建 Web 前端。”——这不再是梦想,而是由 Reflex 带来的现实。 过去,构建一个现代 Web 应用意味着你要学会前端(React/JS/HTML/CSS) 后端(Flask/Django) API 交互&#xff08…

Vue实战(08)解决 Vue 项目中路径别名 `@` 在 IDE 中报错无法识别的问题

一、引言 ​ 在 Vue 项目开发过程中,路径别名是一个非常实用的特性,它能够帮助开发者简化文件引用路径,提高代码的可读性和可维护性。其中, 作为一个常见的路径别名,通常被用来指向项目的 src 目录。然而,…

5.学习笔记-SpringMVC(P61-P70)

SpringMVC-SSM整合-接口测试 (1)业务层接口使用junit接口做测试 (2)表现层用postman做接口测试 (3)事务处理— 1)在SpringConfig.java,开启注解,是事务驱动 2)配置事务管理器(因为事务管理器是要配置数据源对象&…

[论文阅读]REPLUG: Retrieval-Augmented Black-Box Language Models

REPLUG: Retrieval-Augmented Black-Box Language Models REPLUG: Retrieval-Augmented Black-Box Language Models - ACL Anthology NAACL-HLT 2024 在这项工作中,我们介绍了RePlug(Retrieve and Plug),这是一个新的检索增强型…

Mysql的深度分页查询优化

一、深度分页为什么慢? 当执行 SELECT * FROM orders ORDER BY id LIMIT 1000000, 10 时: MySQL 会扫描前 1,000,010 行,丢弃前 100 万行,仅返回 10 行。偏移量(offset)越大,扫描行数越多&…

最新扣子(Coze)案例教程:Excel数据生成统计图表,自动清洗数据+转换可视化图表+零代码,完全免费教程

大家好,我是斜杠君。 知识星球群有同学和我说每天的工作涉及很多数据表的重复操作,想学习Excel数据表通过大模型自动转数据图片的功能。 今天斜杠君就带大家一起搭建一个智能体,以一个销售行业数据为例,可以快速实现自动清洗Exc…

Uniapp 中缓存操作指南

在 Uniapp 中,你可以使用三种方式操作缓存:同步方法、异步方法和 Vuex 持久化存储。以下是详细的设置、获取和清除缓存的方法: 1. 同步方法 设置缓存 uni.setStorageSync(key, value); // 示例 uni.setStorageSync(token, abc123); 获取缓存 const value = uni.getStor…

k8s的yaml文件里的volume跟volumeMount的区别

volume 是 Pod 级别的资源,用于定义存储卷。它是一个独立于容器的存储资源,可以被一个或多个容器共享使用。volume 的定义位于 Pod 的 spec.volumes 部分。 特点 独立性:volume 是 Pod 的一部分,而不是容器的一部分。它独立于容…

梅毒单阳能否通过国企体检?

国企体检通常会参照公务员体检标准进行,梅毒检测是其中的常规项目。 一、明确“梅毒单阳”的定义 检测指标解析 TPPA阳性RPR阴性:可能为既往感染已治愈,或极早期/晚期梅毒; RPR阳性TPPA阴性:需警惕假阳性&#xff08…

Python 爬虫实战 | 企名科技

文章目录 一、企名科技1、目标网站2、网站特点3、确定解密位置4、扣js代码 一、企名科技 1、目标网站 网址:https://wx.qmpsee.com/articleDetail?idfeef62bfdac45a94b9cd89aed5c235be目标数据:获取消费行业研究下面的13篇文章数据 2、网站特点 服…

Pikachu靶场

本质是信任了不可信的客户端输入。防御核心: 永不信任客户端提交的权限参数(如 user_id, role)。强制服务端校验用户身份与操作权限。定期审计权限模型,避免业务迭代引入新漏洞。 水平越权 1,按照网站的提示要求登录 进…

C++区别于C语言的提升用法(万字总结)

1.namespace产生原因 在C语言中,变量,函数,以至于类都是大量存在的,因此会产生大量的名称存在于全局作用域中,可能产生很多冲突,至此c的祖师爷为避免命名冲突和名字的污染,造出来了关键字names…

数据库day-07

一、实验名称和性质 子查询 验证 设计 二、实验目的 1.掌握子查询的嵌套查询; 2.掌握集合操作 3.了解EXISTS嵌套查询方法; 三、实验的软硬件环境要求 硬件环境要求: PC机(单机) 使用的软件名称、版本号以及模块…

【前端】【业务场景】【面试】在前端开发中,如何实现文件的上传与下载功能,并且处理可能出现的错误情况?

前端文件上传与下载攻略 本文目标&#xff1a;帮你快速掌握文件上传 & 下载的核心实现方式&#xff0c;并在常见出错场景下保持“优雅不崩溃”。 一、文件上传 1. 基础结构 <input type"file" id"fileInput" /> <button id"uploadBtn&…

Kafka 消息积压监控和报警配置的详细步骤

Kafka 消息积压监控和报警配置的详细步骤示例&#xff0c;涵盖常用工具&#xff08;如 Prometheus Grafana、云服务监控&#xff09;和自定义脚本方法&#xff1a; 一、监控配置 方法1&#xff1a;使用 Prometheus Grafana kafka-exporter 步骤1&#xff1a;部署 kafka-ex…

【C++】内存管理:内存划分、动态内存管理(new、delete用法)

文章目录 一、C/C中的内存划分二、C语言中动态内存管理方式三、C中动态内存管理方式1、new、delete基本用法(1)、内置类型(2)、自定义类型 2、operator new与operator delete函数3、new和delete的实现原理&#xff08;1&#xff09;内置类型&#xff08;2&#xff09;自定义类型…

C# 实战_RichTextBox选中某一行条目高亮,离开恢复

C# 中控件richtextbox中某一行的条目内容高亮&#xff0c;未选中保持不变。当鼠标点击某一行的条目高亮&#xff0c;离开该条目就恢复默认颜色。 运行效果&#xff1a; 核心代码实现功能&#xff1a; //高亮指定行的方法private void HighlightLine(RichTextBox rtb,int lineI…