建造者模式:学个设计模式还和人生扯上关系了?

2023-12-25 11:38

本文主要是介绍建造者模式:学个设计模式还和人生扯上关系了?,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

build

建造者模式 🔨

指将一个复杂对象的构造与它的表示分离,使同样的构建过程可以创建不同的表示

根据建造者模式的定义,我们可以先简单的了解一下建造者模式要解决的问题,它是指将一个复杂对象的构建与它的表示分离,这句话的意思是指一个对象的构建过程与表示不再绝对。即一个构建过程对应多个结果,这取决于客户端如果指挥构建者进行对象的构建。这里的构建者就是我们接下来要讲的建造者模式内容。

理解程序中的建造 🗯

对于建造这个词语没什么好说的,在软件程序中建造是什么呢?我相信看到下面这个例子你应该就已经掌握了什么是建造者模式,当然这还不够,让我们慢慢来。

JDK 中的 StringBuilder

public class StringBuilderTest {@Testvoid test(){StringBuilder stringBuilder = new StringBuilder();stringBuilder.append(1).append("个张三,和").append(4).append("个李四");System.out.println(stringBuilder.toString());}
}
1个张三,和4个李四
Process finished with exit code 0

上面的例子是妇孺皆知的 JDK 中提供的一个为了解决复杂 String 对象的 String 对象生成器。它还有个孪生姐夫StringBuffer用在并发环境下。

Netty 中的 ServerBootstrap

再比如这个,netty 的启动器

        ServerBootstrap bootstrap = new ServerBootstrap();bootstrap.group(parentGroup, childGroup).channel(NioServerSocketChannel.class).option(ChannelOption.SO_BACKLOG, 128).childHandler(new NettyProtobufChannelInitializer());try {ChannelFuture sync = bootstrap.bind(2333).sync();sync.channel().closeFuture().sync();} catch (InterruptedException e) {e.printStackTrace();}

通过建造者 ServerBootstrap 来完成一个启动器的构建,同一个构造过程,却有着千差万别的结果。

lvgo 的 Slient 并发任务处理器

如果建造者被我们自己应用的话,我个人将它使用到了程序插拔配置上了,就像 netty 的启动器一样。

        new TaskHandler<String>(testData) {@Overridepublic void run(String s) {try {Thread.sleep(1000L);} catch (InterruptedException e) {e.printStackTrace();}log.info("第" + s + "个任务" + Thread.currentThread());}}.sync(false).overRun(() -> {log.debug("我所有的任务执行结束了");}).execute(10);

上面我写的这个组件已发布到 maven 仓库,源码仓库:https://github.com/lvgocc/silent

<dependency><groupId>org.lvgo</groupId><artifactId>silent</artifactId><version>1.0</version>
</dependency>

通过上面的几个例子我们大概知道什么是建造者模式了,它可以通过同一个构造过程来创建出不同的表示对象,比如

  • StringBuilder 通过不同的参数传入 append 方法,得到结果是不一样的;
  • ServerBootstrap 的不同参数设置,启动出来的 netty 服务端有着不同作用;
  • TaskHandler 通过指定不同的参数,可以使任务的执行效果产生不同的变化;

建造者模式类图 📌

注:在 GOF 的原著中对建造模式的理解与本篇差别较大。所以类图看起来会和很多资料中有所差异,望读者知悉。

build-UML

GOF 中定义的建造者类图

gof-build-UML

这里说明一下,GOF 的建造者模式中体现的是将要构建的对象、构建者、具体构建者、指挥者4部分独立开来,可以做很好的水平扩展。而 lvgo 将建造者的抽象类与具体的构建者合成一个,通过参数的方式将具体的构建者体现出来。将指挥者的角色延迟到了客户端,直接由客户端 client 来代替 Director 的工作。

代码 📄

避免篇幅过长,完整代码及单元测试结果点击查看 https://github.com/lvgocc/java-design-patterns/tree/main/build

为了能够更好的去理解 lvgo 与 GOF 中类图的差异,这里准备了两种写法,以诠释上面的说明。

GOF 类图的实现

public abstract class Builder {protected PlayerRole playerRole = new PlayerRole();abstract void setHairColor();abstract void setShape();abstract void setSkinColour();PlayerRole build() {return playerRole;}
}
public class Director {private final Builder builder;public Director(Builder builder) {this.builder = builder;}public PlayerRole construct() {builder.setHairColor();builder.setShape();builder.setSkinColour();return builder.build();}public PlayerRole construct2() {builder.setHairColor();return builder.build();}public PlayerRole construct3() {builder.setSkinColour();return builder.build();}
}
public class PlayerRoleBuilder extends Builder {@Overridevoid setHairColor() {playerRole.setHairColor("褐色");}@Overridevoid setShape() {playerRole.setShape("健硕");}@Overridevoid setSkinColour() {playerRole.setSkinColour("古铜色");}
}
public class PlayerRole {private String hairColor;private String shape;private String skinColour;
}

测试类

    void build() {Builder playerRoleBuilder = new PlayerRoleBuilder();Director playerRoleBuildDirector = new Director(playerRoleBuilder);PlayerRole construct = playerRoleBuildDirector.construct();}

结果

construct = PlayerRole{hairColor='褐色', shape='健硕', skinColour='古铜色'}

个人觉得这种写法稍为复杂,不过他的水平扩展性和隔离性都比较好。

lvgo 整理的写法如下

public class PlayerRole {private String hairColor;private String shape;private String skinColour;
}
public class PlayerRoleBuilder {private final PlayerRole playerRole = new PlayerRole();PlayerRoleBuilder hairColor(String color) {playerRole.setHairColor(color);return this;}PlayerRoleBuilder shape(String shape) {playerRole.setShape(shape);return this;}PlayerRoleBuilder skinColour(String skinColour) {playerRole.setSkinColour(skinColour);return this;}PlayerRole build() {return playerRole;}
}

测试

    @Testvoid test(){PlayerRoleBuilder playerRoleBuilder = new PlayerRoleBuilder();playerRoleBuilder.hairColor("红色").shape("健硕").skinColour("古铜色");PlayerRole build = playerRoleBuilder.build();System.out.println("build = " + build);}

结果

build = PlayerRole{hairColor='红色', shape='健硕', skinColour='古铜色'}

总结 🐱‍💻

相同的资源,不同的结果是我对建造者模式创建对象的理解。就像建造我们的人生,提供了相同的世界,相同的空气,每个个体的表现均不同。

通过使用建造者模式,我们可以更加灵活的去处理一个构建过程复杂的对象。将它的构建过程与表示分离开。例如如果你正在为一长串的 set 方法苦恼的时候可以考虑一下建造者模式。它使代码更整洁,可读性更好。

xxx.setA();
xxx.setB();
xxx.setC();
xxx.setD();
xxx.setE();
xxx.A().B().C().D().E().build();

当你想要给一个对象组装一个特有的结果的时候,不妨试试 GOF 的思路,很不错的。

缺点:

建造者模式因为需要维护一个单独的建造者类,同时要为每个属性单独维护一个方法,当类中有属性调整的时候,要一起调整对应建造者中的方法,这也是随它的优势而带来的一些副作用。但如果有需要它的地方尽管去用。没有什么比混沌的代码更糟糕的事情了。

案例应用

这里为了应读者要求,想有对应的案例可以参考,不然不清楚设计模式到底在什么地方用。

  1. 餐饮系统有23道素材、18道荤菜,老板今天推出 8 种 2素 1 荤套餐,你如何实现?
  2. 试想一下在我的世界(mc)中,提供了各种不同的道具,相同的道具组合,你做出来的房子和我做出来的房子看起来不那么一样。
  3. 在塔防类游戏中,同一个射手,每次攒钱给他升级,最终有的变成了单体攻击高的神射手,有的变成散射群里攻击低的散箭手。

返璞归真

我认为学习设计模式的过程就像拿到一台游戏机,玩到最后,我都会拆开看看里面是什么,而早已不关心游戏好不好玩了。

知识也是一样,知其然而知其所以然。

我们为了学会使用某种东西看他的操作手册就可以了;

我们如果想要学会修某种东西就需要看他的设计手册;

当我们想要创造某种东西,你就需要掌握很多很多设计手册,将他们的经验进行吸收、消化、提炼。才能有更好的结果。

当然,如果你只想会用,有一份差不多的操作指南也就够了。

抱歉这一篇说了一些题外话。

写在最后

Java 设计模式专题,共23 种设计模式。内容来自个人学习理解消化的结果,谈不上教程,只望记录于此同你分享。希望能够和大家一起进步、成长。为了梦想,学习技术。如果你觉得文章对你有帮助,希望随便点赞、关注、分享、给个 star 支持一下。感激涕零🎈。

⭐https://github.com/lvgocc/java-design-patterns

星尘的一个朋友 亦或繁星、亦或尘埃。星尘,为了梦想,学习技术。

关注公众号,回复“加群”,和 lvgo 一起学习设计模式。坚决维护群内环境,给大家提供一个良好的学习交流环境。

星尘的一个朋友

这篇关于建造者模式:学个设计模式还和人生扯上关系了?的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/535384

相关文章

在JS中的设计模式的单例模式、策略模式、代理模式、原型模式浅讲

1. 单例模式(Singleton Pattern) 确保一个类只有一个实例,并提供一个全局访问点。 示例代码: class Singleton {constructor() {if (Singleton.instance) {return Singleton.instance;}Singleton.instance = this;this.data = [];}addData(value)

POJ1269 判断2条直线的位置关系

题目大意:给两个点能够确定一条直线,题目给出两条直线(由4个点确定),要求判断出这两条直线的关系:平行,同线,相交。如果相交还要求出交点坐标。 解题思路: 先判断两条直线p1p2, q1q2是否共线, 如果不是,再判断 直线 是否平行, 如果还不是, 则两直线相交。  判断共线:  p1p2q1 共线 且 p1p2q2 共线 ,共线用叉乘为 0  来判断,  判断 平行:  p1p

pip-tools:打造可重复、可控的 Python 开发环境,解决依赖关系,让代码更稳定

在 Python 开发中,管理依赖关系是一项繁琐且容易出错的任务。手动更新依赖版本、处理冲突、确保一致性等等,都可能让开发者感到头疼。而 pip-tools 为开发者提供了一套稳定可靠的解决方案。 什么是 pip-tools? pip-tools 是一组命令行工具,旨在简化 Python 依赖关系的管理,确保项目环境的稳定性和可重复性。它主要包含两个核心工具:pip-compile 和 pip

模版方法模式template method

学习笔记,原文链接 https://refactoringguru.cn/design-patterns/template-method 超类中定义了一个算法的框架, 允许子类在不修改结构的情况下重写算法的特定步骤。 上层接口有默认实现的方法和子类需要自己实现的方法

【iOS】MVC模式

MVC模式 MVC模式MVC模式demo MVC模式 MVC模式全称为model(模型)view(视图)controller(控制器),他分为三个不同的层分别负责不同的职责。 View:该层用于存放视图,该层中我们可以对页面及控件进行布局。Model:模型一般都拥有很好的可复用性,在该层中,我们可以统一管理一些数据。Controlller:该层充当一个CPU的功能,即该应用程序

迭代器模式iterator

学习笔记,原文链接 https://refactoringguru.cn/design-patterns/iterator 不暴露集合底层表现形式 (列表、 栈和树等) 的情况下遍历集合中所有的元素

《x86汇编语言:从实模式到保护模式》视频来了

《x86汇编语言:从实模式到保护模式》视频来了 很多朋友留言,说我的专栏《x86汇编语言:从实模式到保护模式》写得很详细,还有的朋友希望我能写得更细,最好是覆盖全书的所有章节。 毕竟我不是作者,只有作者的解读才是最权威的。 当初我学习这本书的时候,只能靠自己摸索,网上搜不到什么好资源。 如果你正在学这本书或者汇编语言,那你有福气了。 本书作者李忠老师,以此书为蓝本,录制了全套视频。 试

利用命令模式构建高效的手游后端架构

在现代手游开发中,后端架构的设计对于支持高并发、快速迭代和复杂游戏逻辑至关重要。命令模式作为一种行为设计模式,可以有效地解耦请求的发起者与接收者,提升系统的可维护性和扩展性。本文将深入探讨如何利用命令模式构建一个强大且灵活的手游后端架构。 1. 命令模式的概念与优势 命令模式通过将请求封装为对象,使得请求的发起者和接收者之间的耦合度降低。这种模式的主要优势包括: 解耦请求发起者与处理者

springboot实战学习(1)(开发模式与环境)

目录 一、实战学习的引言 (1)前后端的大致学习模块 (2)后端 (3)前端 二、开发模式 一、实战学习的引言 (1)前后端的大致学习模块 (2)后端 Validation:做参数校验Mybatis:做数据库的操作Redis:做缓存Junit:单元测试项目部署:springboot项目部署相关的知识 (3)前端 Vite:Vue项目的脚手架Router:路由Pina:状态管理Eleme

状态模式state

学习笔记,原文链接 https://refactoringguru.cn/design-patterns/state 在一个对象的内部状态变化时改变其行为, 使其看上去就像改变了自身所属的类一样。 在状态模式中,player.getState()获取的是player的当前状态,通常是一个实现了状态接口的对象。 onPlay()是状态模式中定义的一个方法,不同状态下(例如“正在播放”、“暂停