08.哲说建造者模式(Builder Pattern)

“The odds that we’re in ‘base reality’ is one in billions.” —— Elon Musk
这段话出自马斯克在2016年的一次演讲,“人类活在真实世界的几率,可能不到十亿分之一”。此言一出,可谓一石激起千层浪。有人嘲讽马斯克是“语不惊人死不休”,也有人对他的言论深信不疑,更多的人则是把这种言论当作茶余饭后消遣的谈资。在这里插入图片描述
笔者对于 “世界是否真的真实” 这一问题的结果并不狂热,但我对于马斯克说出这句话的时间点很感兴趣,我可以帮大家捋一下前后的时间线。
2016年,ChatGPT诞生,而马斯克正是OpenAI的联合创办人之一
2017年,ChatGPT正式推出
2018年,ChatGPT开始全面发展,在社区活跃度直线上升
2019年,OpenAI从非营利性组织转型为“利润上限(caped-profit)”公司后,马斯克离开
2020年至今,ChatGPT逐渐火爆出圈,可以说改变人们的生活方式去日不远

在这里插入图片描述
微妙吗?“日心说” 源于计算结果,马斯克的话是否也源于即有结果的合理推测呢?这个话题可能每个人都会有自己的看法。
“天下万物生于有,有生于无。”——《道德经·第四十章》


一言

建造者模式是一步步创建一个复杂的对象,它允许用户只通过指定复杂对象的类型和内容就可以构建他们而不需要知道内部具体的构建细节。


概述

“天下万物生于有,有生于无”。如果现在我告诉你,你可以创建一个世界,你是一个造物主,但是你要把自己藏起来,不能让这个世界的小生命知道你的存在,你会以什么样的逻辑来设计第一个模型?
有人说,我要信“码”由缰,懒得装;有人说,我要挖空细节演好上帝。
这其实就是设计模式有趣的地方,它松散无骨,语气平和,不按它的来这个世界的太阳照常升起,但按它的要求做,这个世界会和谐的像假的一样。
这一次,我想让阅读我博客的你和我一起演一次“造物主”,从神的角度,俯视设计模式中的“建造者模式”。

一个看似无关紧要且过分晦涩的概念

建造者模式(Builder Pattern) 又叫生成器模式,是一种对象构建模式。它可以将复杂对象的建造过程抽象出来(抽象类别),使这个抽象过程的不同实现方法可以构造出不同表现 (属性) 的对象。


创世纪

好了,上帝们,我们开始。
我们假定创造一个世界的过程是:创建星球环境,播种生命,注入意识。但是每个世界肯定有不同的差别(作为上帝,我们不可能只创建了一个世界对不?)。那么自然有的世界的星球环境是单星结构,而有的是三体结构(很熟悉吧);生命形态肯定也不尽相同,碳基生物还是硅基生物或者其它神奇的生命体;意识就更是千变万化了。
在这里插入图片描述


信“码”由缰的上帝

如果我是那个只想快速完成KPI,不考虑运行后果的上帝,我可能会这样设计。
在这里插入图片描述

代码实现

一个抽象

public abstract class AbstractHouse {
    //基础环境
    public abstract void buildEarth();
    //创造生命
    public abstract void humanBeing();
    //意识觉醒
    public abstract void aware();
    //建造
    public void build(){
        buildEarth();
        humanBeing();
        aware();
    }
}

实现人类文明

public class HumanWorld extends AbstractHouse{
    @Override
    public void buildEarth() {
        System.out.println("太阳系三号行星已构建");
    }
    @Override
    public void humanBeing() {
        System.out.println("灵长类动物已生成");
    }
    @Override
    public void aware() {
        System.out.println("人类意识觉醒,温良恭俭让");
    }
}

实现外星文明

public class ETWorld extends AbstractHouse{
    @Override
    public void buildEarth() {
        System.out.println("猎户座九号行星已构建");
    }
    @Override
    public void humanBeing() {
        System.out.println("硅基生物已生成");
    }
    @Override
    public void aware() {
        System.out.println("异形意识觉醒,碾碎他们");
    }
}

经典反思

有什么问题?
优点自不必多说,两分钟的设计难度简单,易操作。
问题就是这个设计结构太简单了,上帝不会这么简单的去创建一个世界的。
没有任何的缓存层对象,程序可以说几乎没有可扩展和维护的空间。把产品(世界)和创建产品的过程(创世过程)完全封装在一起,耦合度太高了。

那么我们如何化腐朽为神奇呢?这就引出了建造者模式。


神之一手

先来了解下建造者模式的四个角色

  1. Product (产品角色) : 一个具体的产品对象;
  2. Builder (抽象建造者): 创建一个Product对象的各个部件指定的接口/抽象类;
  3. ConcreteBuilder (具体建造者):实现接口,构建和装配各个部件;
  4. Director (指挥者):构建一个Builder接口的对象,它主要是用于创建一个复杂的对象。它主要有两个作用,一是:隔离了客户与对象的生产过程;二是:负责控制产品对象的生产过程。

图解

在这里插入图片描述

代码

产品类

public class World{
    private String space;//环境
    private String alive;//生命
    private String aware;//意识
	//setter&getter
}

抽象建造者

public abstract class WorldBuilder {
    protected  World world = new World();
    //将建造的流程写好,抽象的方法
    public abstract void buildEarth();
    public abstract void humanBeing();
    public abstract void aware();
    //建造世界,将产品返回
    public World build(){
        return world;
    }
}

地球文明建造者

public class EarthBuilder extends WorldBuilder{
    @Override
    public void buildEarth() {
        System.out.println("太阳系三号行星");
        world.setSpace("地球");
    }

    @Override
    public void humanBeing() {
        System.out.println("地球生命");
        world.setAlive("人类");
    }

    @Override
    public void aware() {
        System.out.println("地球人意识");
        world.setAware("温良恭俭让");
    }
}

外星文明建造者

public class ETBuilder extends WorldBuilder{
    @Override
    public void buildEarth() {
        System.out.println("猎户座九号行星");
        world.setSpace("赛博坦");
    }

    @Override
    public void humanBeing() {
        System.out.println("外星生命");
        world.setAlive("硅基生物");
    }

    @Override
    public void aware() {
        System.out.println("外星人意识");
        world.setAware("活下去,撕碎他们");
    }
}

指挥者

public class WorldDirector {
    WorldBuilder worldBuilder = null; 

    //方式1:构造器传入 worldBuilder
    public WorldDirector (WorldBuilder worldBuilder ) {
        this.worldBuilder = worldBuilder ;
    }

    //方式2:通过setter 传入 worldBuilder
    public void setWorldBuilder(WorldBuilder worldBuilder ) {
        this.worldBuilder = worldBuilder ;
    }

    //如何建造世界的流程,交给指挥者
    //创世
    public World constructWorld(){
        worldBuilder.buildEarth();
        worldBuilder.humanBeing();
        worldBuilder.aware();
        return worldBuilder.build();
    }
}

测试类

public class Client {
    public static void main(String[] args) {
        WorldDirector worldDirector = new WorldDirector (new EarthBuilder());
        World earth = worldDirector.constructWorld();
        
        worldDirector.setWorldBuilder(new ETBuilder());
        World et = worldDirector.constructWorld();

        System.out.println("地球人基本意识:"+earth.getAware());
        System.out.println("外星人基本意识:"+et.getAware());
    }
}

测试结果

在这里插入图片描述


Builder Pattern在JDK源码中的应用

其实设计模式离我们的日常开发非常近,建造者模式也不例外。比如StringBuilder,从名字看也差不多能猜到coder的思想和意图。
在这里插入图片描述
通过阅读Appendable、AbstractStringBuilder和StringBuilder的源码,我们会发现:

  • Appendable 接口定义了多个append方法(抽象方法),即Appendable 为抽象建造者,定义了抽象方法
  • AbstractStringBuilder 实现了 Appendable 接口方法,这里的AbstractstringBuilder 已经是建造者,只是不能实例化
  • StringBuilder 即充当了指挥者角色,同时充当了具体的建造者,建造方法的实现是由 AbstractStringBuilder 完成,而StringBuilder 继承了AbstractStringBuilder

客户端(使用程序)不必知道产品内部组成的细节,将产品本身与产品的创建过程解耦,使得相同的创建过程可以创建不同的产品对象每一个具体建造者都相对独立,而与其他的具体建造者无关,因此可以很方便地替换具体建造者或增加新的具体建造者,用户使用不同的具体建造者即可得到不同的产品对象。可以更加精细地控制产品的创建过程。将复杂产品的创建步骤分解在不同的方法中,使得创建过程更加清晰,也更方便使用程序来控制创建过程。增加新的具体建造者无须修改原有类库的代码,指挥者类针对抽象建造者类编程系统扩展方便,这也符合此前我们强调过的“开闭原则”。建造者模式所创建的产品一般具有较多的共同点,其组成部分相似,如果产品之间的差异性很大,则不适合使用建造者模式,因此其使用范围受到一定的限制。如果产品的内部变化复杂,可能会导致需要定义很多具体建造者类来实现这种变化,导致系统变得很庞大,因此在这种情况下,要考虑选择建造者模式是不是真的是最优解。
其实可以着重理解一下Director的构造这部分,在我看来,Builder Pattern的巧妙之处就在于它优雅的将一颗“种子”丢到了一个星球上,在“种子”发芽之前我们无需关注这颗种子的大小、品相。“万物生于有,有生于无”。

相信能耐心读到这里的同学应该会有一种奇怪的感觉,建造者模式怎么有点类似于抽象工厂模式呢?

那么抽象工厂模式是什么?工厂模式又是什么?它们和建造者模式又有什么异同呢?卖个关子,明年(下周)讲。

预祝大家新年快乐哈~


关注我,共同进步,每周至少一更,来聊的不只是代码。——Wayne

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

GBASE南大通用-GBase 8s数据库日志模式及切换

一、 GBase 8s数据库共有以下 4 种日志模式:无日志模式、缓冲日志模式、无缓冲日志模式、ANSI 模式。详细介绍如下: 1、无日志模式(Non logging): 采用无日志模式时,所有 DML 操作都不会被记录到日志中&…

LVS负载均衡配置虚拟引起微服务注册混乱

线上小程序突然报错,查看网关日志,访问下游微服务A时大量报错: 1)检查微服务是否未注册。登录eureka页面,发现三个节点均正常注册 三个微服务节点地址分别为:13.9.1.91:8080,13.9.1.92:8080和1…

ssm504基于web的经典电影推荐网站的设计与实现论文

摘 要 传统办法管理信息首先需要花费的时间比较多,其次数据出错率比较高,而且对错误的数据进行更改也比较困难,最后,检索数据费事费力。因此,在计算机上安装经典电影推荐网站软件来发挥其高效地信息处理的作用&#x…

ROS【一】(ROS的安装(ubuntu20.04))

ROS的安装 ROS的安装 ROS的安装[TOC](ROS的安装) 前言一、更新镜像源1.进入下载地址2.选择自己的系统类型3.选择自己的系统版本 二、ROS安装1.配置公钥2.添加ros源2.安装ros(注意ubuntu版本和ros版本要对应) 三、配置Ros1.设置环境变量2.安装依赖 四、测试Ros1.先重启2.启动Ros…

PiflowX大数据流水线系统

PiflowX大数据流水线系统。支持分布式计算引擎flink和spark。以所见即所得的方式,实现大数据采集、处理、存储与分析流程化配置、运行与智能监控。 PiflowX基于Piflow(PiFlow: 混合型科学大数据流水线系统,包含丰富的处理器组件,…

Flink(十一)【状态管理】

Flink 状态管理 我们一直称 Flink 为运行在数据流上的有状态计算框架和处理引擎。在之前的章节中也已经多次提到了“状态”(state),不论是简单聚合、窗口聚合,还是处理函数的应用,都会有状态的身影出现。状态就如同事务…

HackTheBox - Medium - Linux - Interface

Interface Interface 是一种中等难度的 Linux 机器,具有“DomPDF”API 端点,该端点通过将“CSS”注入处理后的数据而容易受到远程命令执行的影响。“DomPDF”可以被诱骗在其字体缓存中存储带有“PHP”文件扩展名的恶意字体,然后可以通过从其…

如何获取永久头像地址(非临时)微信小程序

先亮结果: 小程序端: 服务器端: 详细代码: 博文仅针对这一个功能,其它的比如wxml和wxss设置,或者微信昵称的获取就不多介绍了。 找了很久也没有找到真实的图片链接地址的获取方式。。。如果有大佬知道如…

竞赛保研 基于机器视觉的12306验证码识别

文章目录 0 简介1 数据收集2 识别过程3 网络构建4 数据读取5 模型训练6 加入Dropout层7 数据增强8 迁移学习9 结果9 最后 0 简介 🔥 优质竞赛项目系列,今天要分享的是 基于机器视觉的12306验证码识别 该项目较为新颖,适合作为竞赛课题方向…

发布自己的npm包

前提条件:已经申请好了npm账号 npm的注册地址: npm注册地址, 按照上面的描述注册就可以,本文赘述具体的注册过程 1. 登陆npm 如果使用了镜像,需要切换镜像 npm config set registry https://registry.npmjs.org/ 控制台使用命令, 输入用户名和密码以及邮箱,然后按回…

VSCODE 修改Test模式下的的java jvm堆内存大小

在settings.json中添加如下语句 "java.test.config": {"vmArgs": ["-Xmx12G"]},

pycharm找回误删的文件和目录

昨天不知道做了什么鬼操作,可能是运行了几个git命令,将项目里面的几个文件删除了,有点懵。 我知道pycharm可以找回文件的历史修改记录,但是对于删除的文件能否恢复,一直没试过。 找到删除文件的目录,点击右…

【C语言】数据结构——带头双链表实例探究

💗个人主页💗 ⭐个人专栏——数据结构学习⭐ 💫点击关注🤩一起学习C语言💯💫 目录 导读:1. 双链表结构特征2. 实现双向循环链表2.1 定义结构体2.2 创造节点2.3 双向链表初始化2.4 双向链表打印2…

【Unity动画系统】Animator有限状态机参数详解

👨‍💻个人主页:元宇宙-秩沅 👨‍💻 hallo 欢迎 点赞👍 收藏⭐ 留言📝 加关注✅! 👨‍💻 本文由 秩沅 原创 👨‍💻 收录于专栏:Uni…

攻防技术1-网络攻击(HCIP)

目录 一、网络攻击方式分类 1、被动攻击: 2、主动攻击: 3、中间人攻击: 二、网络攻击报文类型分类: 1、流量型攻击 2、单包攻击 三、流量型攻击防范技术 1、DNS Request Flood攻击 攻击原理 DNS交互过程 2、TCP类报文…

统信UOS及麒麟KYLINOS操作系统上设置GRUB密码

原文链接:给单用户模式上一层保险!!! hello,大家好啊!今天我要给大家介绍的是在统信UOS及麒麟KYLINOS操作系统上设置GRUB密码的方法。GRUB(GRand Unified Bootloader)是Linux系统中的…

【Vue】使用Axios请求下载后端返回的文件流,并能够提示后端报错信息

【需求】使用Axios请求下载后端返回的文件流,下载失败时提示信息不写死,按照后端返回的信息进行提示。 一、需求分析 看到这个需求的时候,有人可能会很疑惑,这不是直接就能获取到吗,直接message.error()弹框就完事了&…

J1 - ResNet-50实战

🍨 本文为🔗365天深度学习训练营 中的学习记录博客🍖 原作者:K同学啊 | 接辅导、项目定制 目录 环境步骤环境设置数据准备图像信息查看 模型设计模型训练模型效果展示 总结与心得体会 环境 系统: Linux语言: Python3.8.10深度学习…

MySQL MVCC精讲

版本链 我们前面说过,对于使用InnoDB存储引擎的表来说,它的聚簇索引记录中都包含两个必要的隐藏列(row_id并不是必要的,我们创建的表中有主键或者非NULL的UNIQUE键时都不会包含row_id列): trx_id&#xff…