构造者模式的实现

引言——构造复杂对象的艺术

软件工程中,构造复杂对象的艺术被巧妙地封装在构造者模式(Builder Pattern)中。这种设计模式不仅提供了一种清晰且灵活的方式来构建复杂对象,还使得代码更具可读性和可维护性。构造者模式的核心思想是将一个复杂对象的构建过程与其表示分离,使得同样的构建过程可以创建不同的表示。

构造者模式下的蟹堡王

在《海绵宝宝》动画片中,蟹堡王可谓是比基尼海滩最著名的快餐店,其中就属蟹黄堡最出名(常常受到痞老板觊觎)。蟹堡王还是海绵宝宝、章鱼哥工作的地方,老板则是蟹老板。

在这里插入图片描述

我们可以取构造者模式为视角,看下蟹黄堡的制作过程中,各个角色的构成成分。

产品(Product):毋庸置疑,肯定是蟹黄堡

  蟹黄堡由多个部分组成,包括面包、肉饼、生菜、番茄、奶酪、洋葱、酸黄瓜和特制酱料。

构造者(Builder):蟹黄堡的制作步骤

  定义制作蟹黄堡的各个步骤,如添加面包、添加肉饼、添加生菜等。

具体构造者(Concrete Builder):蟹堡王唯一的厨师——海绵宝宝

  在动画片里,由海绵宝宝负责按照特定的顺序和配方制作蟹黄堡。

指挥者(Director):蟹堡王的黑心老板——蟹老板

  蟹老板负责指挥海绵宝宝制作美味蟹黄堡。

蟹黄堡的制作流程

可以看到构造者模式应用下的在蟹堡王,蟹黄堡的制作过程会被分解为多个步骤,每个步骤都由海绵宝宝来执行,而蟹老板则负责指挥整个制作过程。这种模式使得蟹黄堡的制作过程既灵活又可控。
在这里插入图片描述

1. 首先是定义产品类——蟹黄堡

import lombok.Data;@Data
public class KrabbyPatty {private String bread;private String patty;private String lettuce;private String tomato;private String cheese;private String onion;private String pickle;private String sauce;private String love;@Overridepublic String toString() {return "KrabbyPatty [bread=" + bread + ", patty=" + patty + ", lettuce=" + lettuce + ", tomato=" + tomato + ", cheese=" + cheese + ", onion=" + onion + ", pickle=" + pickle + ", sauce=" + sauce + ", love=" + love + "]";}
}

2. 然后是定义构造者接口——蟹黄堡的制作步骤

public interface KrabbyPattyBuilder {void buildBread();void buildPatty();void buildLettuce();void buildTomato();void buildCheese();void buildOnion();void buildPickle();void buildSauce();void buildLove();KrabbyPatty getKrabbyPatty();
}

3. 接着是创建一个具体构造者——海绵宝宝

public class Spongebob implements KrabbyPattyBuilder {private KrabbyPatty krabbyPatty;public Spongebob() {this.krabbyPatty = new KrabbyPatty();}@Overridepublic void buildBread() {krabbyPatty.setBread("面包");}@Overridepublic void buildPatty() {krabbyPatty.setPatty("汉堡肉");}@Overridepublic void buildLettuce() {krabbyPatty.setLettuce("生菜");}@Overridepublic void buildTomato() {krabbyPatty.setTomato("西红柿");}@Overridepublic void buildCheese() {krabbyPatty.setCheese("芝士片");}@Overridepublic void buildOnion() {krabbyPatty.setOnion("洋葱片");}@Overridepublic void buildPickle() {krabbyPatty.setPickle("酸黄瓜");}@Overridepublic void buildSauce() {krabbyPatty.setSauce("秘制酱汁");}public void buildLove() {krabbyPatty.setLove("满满的爱");}@Overridepublic KrabbyPatty getKrabbyPatty() {return krabbyPatty;}
}

4. AndThen!指挥者——蟹老板

public class Krabs {private KrabbyPattyBuilder builder;public Krabs(KrabbyPattyBuilder builder) {this.builder = builder;}public void constructKrabbyPatty() {builder.buildBread();builder.buildPatty();builder.buildLettuce();builder.buildTomato();builder.buildCheese();builder.buildOnion();builder.buildPickle();builder.buildSauce();builder.buildLove();}public KrabbyPatty getKrabbyPatty() {return builder.getKrabbyPatty();}
}

5. 最后,当然是开始享用美味蟹黄堡啦

public class Client {public static void main(String[] args) {KrabbyPattyBuilder builder = new Spongebob();Krabs director = new Krabs(builder);director.constructKrabbyPatty();KrabbyPatty krabbyPatty = director.getKrabbyPatty();System.out.println(krabbyPatty);}}

上面的例子是一个标准的构造者模式。在这个模式中,将蟹黄堡的制作过程与产品互相分离。蟹老板(Krabs)作为指挥者,不需要关心海绵宝宝(具体构造者)是如何构建蟹黄堡的,只需要调用相应的构建方法坐收小钱钱。这正是构造者模式的特点之一:将构建复杂对象的过程分解为多个步骤,并且这些步骤可以灵活组合,从而构建出不同的产品。

标准构造者模式的变种

上面的构建者模式是一个标准的写法,在实际的开发中见到的和应用的构造者模式大多都不会是完全按照这种四个角色来编写,更多的采用了构造者模式的演变版本,以适应不同的需求和场景。例如StringBuilder、Retrofit、OkHttp 等。下面我们来列举几种常用的变种模式写法:

内部构造者(Inner Builder)

这种写法,核心是在产品类内部定义一个静态内部类作为构造者,指挥者(Director)角色通常被省略,因为客户端可以直接使用内部构造者来构建产品。这样可以使得代码更加紧凑和简洁。也是目前最常用的一种构造者模式写法。

@Data
public class KrabbyPatty {private String bread;private String patty;private String lettuce;private String tomato;private String cheese;private String onion;private String pickle;private String sauce;private String love;// 私有构造函数,只能通过内部构造者创建private KrabbyPatty(Spongebob builder) {this.bread = builder.bread;this.patty = builder.patty;this.lettuce = builder.lettuce;this.tomato = builder.tomato;this.cheese = builder.cheese;this.onion = builder.onion;this.pickle = builder.pickle;this.sauce = builder.sauce;this.love = builder.love;}public static Spongebob newBuilder() {return new Spongebob();}public static class Spongebob {private String bread;private String patty;private String lettuce;private String tomato;private String cheese;private String onion;private String pickle;private String sauce;private String love;public Spongebob buildBread(String bread) {this.bread = bread;return this;}public Spongebob buildPatty(String patty) {this.patty = patty;return this;}public Spongebob buildLettuce(String lettuce) {this.lettuce = lettuce;return this;}public Spongebob buildTomato(String tomato) {this.tomato = tomato;return this;}public Spongebob buildCheese(String cheese) {this.cheese = cheese;return this;}public Spongebob buildOnion(String onion) {this.onion = onion;return this;}public Spongebob buildPickle(String pickle) {this.pickle = pickle;return this;}public Spongebob buildSauce(String sauce) {this.sauce = sauce;return this;}public Spongebob buildLove(String love) {this.love = love;return this;}public KrabbyPatty build() {return new KrabbyPatty(this);}}@Overridepublic String toString() {return "KrabbyPatty [bread=" + bread + ", patty=" + patty + ", lettuce=" + lettuce + ", tomato=" + tomato + ", cheese=" + cheese + ", onion=" + onion + ", pickle=" + pickle + ", sauce=" + sauce + ", love=" + love + "]";}

接着是客户端的调用,我们可以明显的发现,与标准的构造者模式相比,内部构造者看起来更加简洁清晰。

public class Clinet {public static void main(String[] args) {KrabbyPatty krabbyPatty = KrabbyPatty.newBuilder().buildBread("面包").buildPatty("肉").buildLettuce("莴苣").buildTomato("西红柿").buildCheese("奶酪").buildOnion("黄瓜").buildPickle("蟹黄").buildSauce("番茄酱").buildLove("满怀诚意的爱").build();System.out.println(krabbyPatty);}  
}  

链式构造者(Fluent Builder)

这种写法,将每个构建方法返回构造者自身,以支持链式调用。指挥者(Director)角色通常被省略,因为客户端可以直接使用链式构造者来构建产品。这使得代码更加简洁和易读。

public class KrabbyPatty {private String bread;private String patty;private String lettuce;private String tomato;private String cheese;private String onion;private String pickle;private String sauce;private String love;// 私有构造函数,只能通过内部构造者创建private KrabbyPatty() {}public static Spongebob newBuilder() {return new Spongebob();}public static class Spongebob {private KrabbyPatty krabbyPatty = new KrabbyPatty();public Spongebob buildBread(String bread) {krabbyPatty.bread = bread;return this;}public Spongebob buildPatty(String patty) {krabbyPatty.patty = patty;return this;}public Spongebob buildLettuce(String lettuce) {krabbyPatty.lettuce = lettuce;return this;}public Spongebob buildTomato(String tomato) {krabbyPatty.tomato = tomato;return this;}public Spongebob buildCheese(String cheese) {krabbyPatty.cheese = cheese;return this;}public Spongebob buildOnion(String onion) {krabbyPatty.onion = onion;return this;}public Spongebob buildPickle(String pickle) {krabbyPatty.pickle = pickle;return this;}public Spongebob buildSauce(String sauce) {krabbyPatty.sauce = sauce;return this;}public Spongebob buildLove(String love) {krabbyPatty.love = love;return this;}public KrabbyPatty build() {return krabbyPatty;}}@Overridepublic String toString() {return "KrabbyPatty [bread=" + bread + ", patty=" + patty + ", lettuce=" + lettuce + ", tomato=" + tomato + ", cheese=" + cheese + ", onion=" + onion + ", pickle=" + pickle + ", sauce=" + sauce + ", love=" + love + "]";}
}

客户端的写法与内部构造者一致,这里就不多赘述了。

与抽象工厂结合使用

这种写法是将构造者模式与抽象工厂模式结合,抽象工厂模式负责创建对象的各个组成部分,而构造者模式负责将这些部分组装成一个复杂的对象。这种分离使得代码更加清晰和易于维护。且使得代码变得更加灵活,后续如果蟹堡王需要增加别的种类的汉堡包,无需修改到现有的蟹黄堡配方,只需要在现有的基础上新增或更改材料即可。

1. 首先定义一个抽象类,由于创建汉堡的各个组成成分。

public abstract class KrabbyPattyFactory {public abstract String createPatty();public abstract String createCheese();public abstract String createSauce();
}

2. 创建具体抽象实现类,返回特定类型的汉堡组成部分

public class RegularPattyFactory extends KrabbyPattyFactory {@Overridepublic String createPatty() {return "汉堡肉饼";}@Overridepublic String createCheese() {return "芝士片";}@Overridepublic String createSauce() {return "番茄酱";}
}

3. 创建主要类,用于让海绵宝宝将这些材料组合成蟹黄堡。

public class KrabbyPatty {private String patty;private String cheese;private String sauce;// 私有构造函数,只能通过内部构造者创建private KrabbyPatty(Spongebob builder) {this.patty = builder.patty;this.cheese = builder.cheese;this.sauce = builder.sauce;}public static Spongebob newBuilder() {return new Spongebob();}public static class Spongebob {private String patty;private String cheese;private String sauce;public Spongebob withFactory(KrabbyPattyFactory factory) {this.patty = factory.createPatty();this.cheese = factory.createCheese();this.sauce = factory.createSauce();return this;}public KrabbyPatty build() {return new KrabbyPatty(this);}}@Overridepublic String toString() {return "KrabbyPatty [patty=" + patty + ", cheese=" + cheese + ", sauce=" + sauce + "]";}
}

4. 使用客户端调用

public class Client {public static void main(String[] args) {KrabbyPattyFactory factory = new RegularPattyFactory();KrabbyPatty krabbyPatty = KrabbyPatty.newBuilder().withFactory(factory).build();System.out.println(krabbyPatty);}
}

总结

构造者模式允许你一步步地构建一个复杂的对象,而不是一次性地创建它。这样做的好处是,你可以灵活地调整对象的各个部分,而不需要为每一种可能的组合都创建一个新的类。就像是在蟹堡王定制蟹黄堡一样,你可以根据自己的需求,让小海绵一步步地构建出你想要的汉堡。这样既灵活又有趣,不是吗?

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

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

相关文章

Unity最新第三方开源插件《Stateful Component》管理中大型项目MonoBehaviour各种序列化字段 ,的高级解决方案

上文提到了UIState, ObjectRefactor等,还提到了远古的NGUI, KBEngine-UI等 这个算是比较新的解决方法吧,但是抽象出来,问题还是这些个问题 所以你就说做游戏是不是先要解决这些问题? 而不是高大上的UiImage,DoozyUI等 Mono管理引用基本用法 ① 添加Stateful Component …

安全测试理论

安全测试理论 什么是安全测试? 安全测试:发现系统安全隐患的过程安全测试与传统测试区别 传统测试:发现bug为目的 安全测试:发现系统安全隐患什么是渗透测试 渗透测试:已成功入侵系统为目标的的攻击过程渗透测试与安全…

“好物”推荐+Xshell连接实例+使用Conda创建独立的Python环境

目录 主题:好易智算平台推荐RTX 4090DGPU实例租用演示安装配置torch1.9.1cuda11.1.1环境引言:算力的新时代平台介绍:技术与信任的结晶使用案例:实际使用展示创建实例开始使用连接实例(下文演示使用Xshell连接&#xff…

昇思25天学习打卡营第二十天|基于MobileNetv2的垃圾分类

打卡营第二十天,今天学习的内容是MobileNet垃圾分类,记录一下学习内容: 学习内容 本文档主要介绍垃圾分类代码开发的方法。通过读取本地图像数据作为输入,对图像中的垃圾物体进行检测,并且将检测结果图片保存到文件中…

【ARM】CCI集成指导整理

目录 1.CCI集成流程 2.CCI功能集成指导 2.1CCI结构框图解释 Request concentrator Transaction tracker Read-data Network Write-data Network B-response Network 2.2 接口注意项 记录一下CCI500的ACE slave interface不支持的功能: 对于ACE-Lite slav…

基于信号处理的PPG信号滤波降噪方法(MATLAB)

光电容积脉搏波PPG信号结合相关算法可以用于人体生理参数检测,如血压、血氧饱和度等,但采集过程中极易受到噪声干扰,对于血压、血氧饱和度测量的准确性造成影响。随着当今社会医疗保健技术的发展,可穿戴监测设备对于PPG信号的质量…

简单的SQL字符型注入

目录 注入类型 判断字段数 确定回显点 查找数据库名 查找数据库表名 查询字段名 获取想要的数据 以sqli-labs靶场上的简单SQL注入为例 注入类型 判断是数字类型还是字符类型 常见的闭合方式 ?id1、?id1"、?id1)、?id1")等,大多都是单引号…

【ASTGCN】模型调试学习笔记--数据生成详解(超详细)

利用滑动窗口生成时间序列 原理图示: 以PEMS04数据集为例。 该数据集维度为:(16992,307,3),16992表示时间序列的长度,307为探测器个数,即图的顶点个数,3为特征数,即流量,速度、平…

期权专题12:期权保证金和期权盈亏

目录 1. 期权保证金 1.1 计算逻辑 1.2 代码复现 1.3 实际案例 2. 期权盈亏 2.1 价格走势 2.2 计算公式 2.2.1 卖出期权 2.2.2 买入期权 免责声明:本文由作者参考相关资料,并结合自身实践和思考独立完成,对全文内容的准确性、完整性或…

[CISCN 2023 华北]normal_snake

[CISCN 2023 华北]normal_snake 源码和依赖 算了直接说吧,不想截图了,就多了一个C3P0和yaml的依赖 然后read路由可以反序列化yaml的Str 我们看到waf 那个String是可以二次反序列化绕过的,然后CUSTOM_STRING1解码后是"BadAttributeValuePairExcept…

【java】力扣 反转链表

力扣 206 链表反转 题目介绍 解法讲解 先定义两个游标indexnull,prenull,反转之后链表应该是5,4,3,2,1,我们先进行2->1的反转,然后再循坏即可 让定义的游标index去存储head.n…

MySQL设置白名单限制

白名单(Whitelist)是一种机制,用于限制哪些主机可以连接到服务器,而阻止其他主机的访问。通过配置白名单,可以增加服务器的安全性,防止未授权的访问。 在MySQL数据库中直接设置白名单访问(即限制…

【触摸屏】【地震知识宣传系统】功能模块:视频 + 知识问答

项目背景 鉴于地震知识的普及对于提升公众防灾减灾意识的重要性,客户希望开发一套互动性强、易于理解的地震学习系统,面向公众、学生及专业人员进行地震知识教育与应急技能培训。 产品功能 系统风格:严谨的设计风格和准确的信息呈现&#…

红酒的艺术之旅:品味、鉴赏与生活的整合

在繁忙的都市生活中,红酒如同一道不同的风景线,将品味、鉴赏与日常生活巧妙地整合在一起。它不仅仅是一种饮品,更是一种艺术,一种生活的态度。今天,就让我们一起踏上这趟红酒的艺术之旅,探寻雷盛红酒如何以…

【qt】如何读取文件并拆分信息?

需要用到QTextStream类 还有QFile类 对于文件的读取操作我们可以统一记下如下操作: 就这三板斧 获取到文件名用文件名初始化文件对象用文件对象初始化文本流 接下来就是打开文件了 用open()来打开文件 用readLine()来读取行数据 用atEnd()来判断是否读到结尾 用split()来获取…

02. Hibernate 初体验之持久化对象

1. 前言 本节课程让我们一起体验 Hibernate 的魅力!编写第一个基于 Hibernate 的实例程序。 在本节课程中,你将学到 : Hibernate 的版本发展史;持久化对象的特点。 为了更好地讲解这个内容,这个初体验案例分上下 2…

go-高效处理应用程序数据

一、背景 大型的应用程序为了后期的排障、运营等,会将一些请求、日志、性能指标等数据保存到存储系统中。为了满足这些需求,我们需要进行数据采集,将数据高效的传输到存储系统 二、问题 采集服务仅仅针对某个需求开发,需要修改…

防火墙小试——部分(书接上回)

toop接上回 1.实验拓扑及要求 前情回顾 DMZ区内的服务器,办公区仅能在办公时间内(9:00 - 18:00)可以访问,生产区的设备全天可以访问. 生产区不允许访问互联网,办公区和游客区允许访问互联网 …

C#统一委托Func与Action

C#在System命名空间下提供两个委托Action和Func,这两个委托最多提供16个参数,基本上可以满足所有自定义事件所需的委托类型。几乎所有的 事件 都可以使用这两个内置的委托Action和Func进行处理。 Action委托: Action定义提供0~16个参数&…

使用亮数据代理IP+Python爬虫批量爬取招聘信息训练面试类AI智能体

本文目录 一、引言二、开发准备三、代码开发四、使用亮数据进行高效爬取4.1 为什么需要亮数据4.2 如何使用亮数据 五、使用数据训练AI智能体六、 总结 一、引言 在当今AI迅速发展的时代,招聘市场正经历着前所未有的变革。传统的招聘方式已难以满足双方的需求。AI智…