【创建者模式】建造者模式

news2024/11/24 20:05:55

文章目录

    • 1、简介
    • 2、结构
    • 3、实现
      • 3.1、需求场景
      • 3.2、产品类
      • 3.3、抽象建造者类
      • 3.4、具体建造者类
      • 3.5、指挥者类
      • 3.6、测试类
      • 3.7、演示结果
    • 4、应用场景
    • 5、实操举例
    • 6、优缺点分析
    • 7、抽象工厂模式区别

1、简介

建造者模式(Builder Pattern)旨在将一个复杂对象的构建表示分离,使得同样的构建过程可以创建不同的表示。简单来说就是使用多个简单的对象一步一步构建成一个复杂的对象。这种类型的设计模式属于创建型模式,是创建对象的最佳方式之一,其主要特点如下:

  • 分离了部件的构造(由Builder来负责)和装配(由Director负责)。 从而可以构造出复杂的对象。这个模式适用于:某个对象的构建过程复杂的情况。
  • 由于实现了构建和装配的解耦。不同的构建器,相同的装配,也可以做出不同的对象;相同的构建器,不同的装配顺序也可以做出不同的对象。也就是实现了构建算法、装配算法的解耦,实现了更好的复用。
  • 建造者模式可以将部件和其组装过程分开,一步一步创建一个复杂的对象。用户只需要指定复杂对象的类型就可以得到该对象,而无须知道其内部的具体构造细节。

通过建造者模式,在用户不知道对象的建造过程和细节的情况下就可以直接创建复杂的对象。

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

2、结构

建造者模式包含如下角色:

  • 抽象建造者类(Builder):这个接口规定要实现复杂对象的那些部分的创建,并不涉及具体的部件对象的创建;

  • 具体建造者类(ConcreteBuilder):继承实现 Builder 抽象类,完成复杂产品的各个部件的具体创建方法。在构造过程完成后,提供产品的实例;

  • 产品类(Product):要创建的复杂对象;

  • 指挥者类(Director):调用具体建造者来创建复杂对象的各个部分,在指导者中不涉及具体产品的信息,只负责保证对象各部分完整创建或按某种顺序创建。

image-20230214215843785

3、实现

3.1、需求场景

可能大家都拥有着自己的一把或多把键盘,而生产键盘是一个复杂的过程,它由键帽、轴体、驱动以及轴下垫等一系列配件组成。熟悉的老手可能了解键帽、轴体等这些都是有不同的,轴体有金粉、风信子、冰淇淋等,键帽有xda、dsa、原厂等。因此针对于复杂的键盘组装过程就可以使用建造者模式;

这里为了方便演示,键盘类只设置了键帽和轴体两个成员属性,并只是用字符串类型代表,旨在演示建造者模式。

3.2、产品类

public class Keyboard {
    /** 键帽 */
    private String keycap;
    
    /** 轴体 */
    private String keyswitch;
    
    // 省略get、set方法
}

3.3、抽象建造者类

public abstract class KeyboardBuilder {
    protected Keyboard keyboard;
    
    public KeyboardBuilder () {
        this.keyboard = new Keyboard();
    }
    
    public abstract void buildKeycap();
    public abstract void buildKeyswitch();
    public abstract Keyboard createKeyboard();
}

3.4、具体建造者类

/**
 * @author xbaozi
 * @version 1.0
 * @classname CherryKeyboardBuilder
 * @date 2023-02-14  22:22
 * @description 用于演示建造者模式-樱桃具体建造者类
 */
public class CherryKeyboardBuilder extends KeyboardBuilder {
    @Override
    public void buildKeycap() {
        keyboard.setKeycap("xda高度键帽");
    }

    @Override
    public void buildKeyswitch() {
        keyboard.setKeyswitch("金粉轴");
    }

    @Override
    public Keyboard createKeyboard() {
        return keyboard;
    }
}

/**
 * @author xbaozi
 * @version 1.0
 * @classname DellyouKeyboardBuilder
 * @date 2023-02-14  22:24
 * @description 用于演示建造者模式-达尔优具体建造者类
 */
public class DellyouKeyboardBuilder extends KeyboardBuilder {
    @Override
    public void buildKeycap() {
        keyboard.setKeycap("dsa高度键帽");
    }

    @Override
    public void buildKeyswitch() {
        keyboard.setKeyswitch("酒红轴");
    }

    @Override
    public Keyboard createKeyboard() {
        return keyboard;
    }
}

3.5、指挥者类

/**
 * @author xbaozi
 * @version 1.0
 * @classname Director
 * @date 2023-02-14  22:31
 * @description 用于演示建造者模式-指挥者类
 */
public class Director {
    private KeyboardBuilder keyboardBuilder;

    public Director(KeyboardBuilder keyboardBuilder) {
        this.keyboardBuilder = keyboardBuilder;
    }

    public Keyboard construct() {
        // 先组装轴体
        keyboardBuilder.buildKeyswitch();
        // 在组装键帽
        keyboardBuilder.buildKeycap();
        // 完成键盘组装
        return keyboardBuilder.createKeyboard();
    }
}

3.6、测试类

/**
 * @author xbaozi
 * @version 1.0
 * @classname BuilderTest
 * @date 2023-02-14  22:36
 * @description 建造者魔术测试类
 */
public class BuilderTest {
    @Test
    public void buiderTest() {
        Keyboard cherryKeyboard = new Director(new CherryKeyboardBuilder()).construct();
        Keyboard dellyouKeyboard = new Director(new DellyouKeyboardBuilder()).construct();
        System.out.println("樱桃键盘:\t" + cherryKeyboard);
        System.out.println("达尔优键盘:\t" + dellyouKeyboard);
    }
}

3.7、演示结果

上面示例是 Builder模式的常规用法,导演类 Director 在 Builder模式中具有很重要的作用,它用于指导具体构建者如何构建产品,控制调用先后次序,并向调用者返回完整的产品类。

image-20230214223958083

4、应用场景

  1. 隔离复杂对象的创建和使用,相同的方法,不同执行顺序,产生不同事件结果

  2. 多个部件都可以装配到一个对象中,但产生的运行结果不相同

  3. 产品类非常复杂或者产品类因为调用顺序不同而产生不同作用

  4. 初始化一个对象时,参数过多,或者很多参数具有默认值

  5. Builder模式不适合创建差异性很大的产品类

  6. 产品内部变化复杂,会导致需要定义很多具体建造者类实现变化,增加项目中类的数量,增加系统的理解难度和运行成本

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

5、实操举例

除了上述的用途外,还有另外一个常用的使用方式,就是当一个类构造器需要传入很多参数时,如果创建这个类的实例,代码可读性会非常差,而且很容易引入错误,此时就可以利用建造者模式进行重构。

ps: 这个例子在开发过程中一般不需要我们自己编写,若有导入Lombok包的话,直接在实体类上方加入@Builder注解即可实现。

这里用项目中常用到的用户类进行举例,用户类一般拥有众多属性,如果直接通过全参构造器进行赋值可读性将会极差,用建造者模式重构如下:

/**
 * @author xbaozi
 * @version 1.0
 * @classname User
 * @date 2023-02-14  22:47
 * @description 建造者模式另一种用途
 */
public class User {
    private String name;
    private String idCard;
    private int age;
    private String gender;
    private String city;

    /**
     * 私有化构造函数,通过建造者进行创建
     * @param builder 建造者
     */
    private User(Builder builder) {
        name = builder.name;
        idCard = builder.idCard;
        age = builder.age;
        gender = builder.gender;
        city = builder.city;
    }

    /**
     * 建造者
     */
    public static final class Builder {
        private String name;
        private String idCard;
        private int age;
        private String gender;
        private String city;

        public Builder name(String name) {
            this.name = name;
            return this;
        }

        public Builder idCard(String idCard) {
            this.idCard = idCard;
            return this;
        }

        public Builder age(int age) {
            this.age = age;
            return this;
        }

        public Builder gender(String gender) {
            this.gender = gender;
            return this;
        }

        public Builder city(String city) {
            this.city = city;
            return this;
        }

        public User build() {
            return new User(this);
        }
    }
}

/**
 * @author xbaozi
 * @version 1.0
 * @classname BuilderTest
 * @date 2023-02-14  22:36
 * @description 建造者模式测试类
 */
public class BuilderTest {

    @Test
    public void builderTest1 () {
        User user1 = new User.Builder()
                .name("陈宝子")
                .age(18)
                .idCard("100861100")
                .city("广东")
                .gender("男")
                .build();

        User user2 = new User.Builder()
                .name("爱吃鱼蛋")
                .age(81)
                .idCard("10010")
                .city("广东")
                .gender("男")
                .build();

        System.out.println(user1);
        System.out.println(user2);
    }
}

运行结果如下,可以看到通过建造者构建得到的用户类是正常的,重构后的代码在使用起来更方便,某种程度上也可以提高开发效率。这里演示的入参只有五个,如果有更多,那么建造者模式的优势则是更为明显:

image-20230214225922494

6、优缺点分析

优点:

  • 使用建造者模式可以使客户端不必知道产品内部组成的细节。
  • 具体的建造者类之间是相互独立的,这有利于系统的扩展。
  • 具体的建造者相互独立,因此可以对建造的过程逐步细化,而不会对其他模块产生任何影响。

缺点:

  • 建造者模式所创建的产品一般具有较多的共同点,其组成部分相似;如果产品之间的差异性很大,则不适合使用建造者模式,因此其使用范围受到一定的限制。
  • 如果产品的内部变化复杂,可能会导致需要定义很多具体建造者类来实现这种变化,导致系统变得很庞大。

image-20230214230156923

7、抽象工厂模式区别

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

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

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

简单来说,抽象工厂更偏向于生产那些固定量产的产品,而建造者模式更偏向于客制化,自由度更高,专注于产品的构建的细节。

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

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

相关文章

SpringCloud:ElasticSearch之索引库操作

ElasticSearch索引库就类似数据库表,mapping映射就类似表的结构。 我们要向ElasticSearch中存储数据,必须先创建“库”和“表”。 1.mapping映射属性 mapping是对索引库中文档的约束,常见的mapping属性包括: type:…

Hyperledger Fabric 2.2版本环境搭建

前言 部署环境: CentOS7.9 提前安装好以下工具 git客户端golangdockerdocker-composecurl工具 以下是个人使用的版本 git: 2.39.2golang: 1.18.6docker: 23.0.3dockkekr-compose: v2.17.2curl: 7.29.0 官方文档参考链接:跳转链接,不同的版本对应的官…

008:Mapbox GL添加比例尺scale功能

第008个 点击查看专栏目录 本示例的目的是介绍演示如何在vue+mapbox中添加比例尺scale功能 。 直接复制下面的 vue+mapbox源代码,操作2分钟即可运行实现效果 文章目录 示例效果配置方式示例源代码(共66行)相关API参考:专栏目标示例效果 配置方式 1)查看基础设置:https…

Linux0.11 管道(十一)

系列文章目录 Linux 0.11启动过程分析(一) Linux 0.11 fork 函数(二) Linux0.11 缺页处理(三) Linux0.11 根文件系统挂载(四) Linux0.11 文件打开open函数(五&#xff09…

fMRI研究 | 社交情境下的混合情绪

导读 背景:神经科学通常都是单独研究各种情绪,而混合的情绪状态(例如愉悦和厌恶、悲伤和快乐的共存)在日常生活中很常见。心理生理学和行为学证据表明,混合情绪可能具有不同于其组成情绪的反应特征。然而,…

什么是JWT?

起源 需要了解一门技术,首先从为什么产生开始说起是最好的。JWT 主要用于用户登录鉴权,所以我们从最传统的 session 认证开始说起。 session认证 众所周知,http 协议本身是无状态的协议,那就意味着当有用户向系统使用账户名称和…

RocketMQ源码分析之监控指标分析

这里是weihubeats,觉得文章不错可以关注公众号小奏技术,文章首发。拒绝营销号,拒绝标题党 Rocketmq版本 version: 5.1.0 背景 继续上次的高可用topic二开已经有了一段时间,现在我们需要对我们的限流数据进行监控,所以现在我们来…

Qt中英文切换(涉及多种场景)

qt中英文切换涉及到一个软件两个文件,分别是QtLinguist、.ts文件和.qm文件。 1、在Pro中添加 TRANSLATIONS en.ts \ch.ts添加这个文件后qmake,然后如下操作点击更新: 这个时候会生成2两个文件en.ts和ch.ts。 2、将这两个文件添加到项目中…

C++ : 构造函数 析构函数

🔵前提引入 : 1如果一个类中什么成员都没有,称为空类,但空类并非什么都没有,在我们没有写任何东西时,编译器会自动生成6个默认成员函数。 2.默认成员函数 : 用户没有显式实现,编译器…

Redis快速上手

Redis快速上手 OVERVIEWRedis快速上手1.redis数据类型2.redis常用命令StringListSetSortedSetHashKey相关3.redis配置文件4.redis数据持久化5.hiredis使用连接数据库执行redis命令函数释放资源程序实例1.redis数据类型 key: 必须是字符串 - “hello” value: 可选的 String类型…

核心业务5:充值业务实现

核心业务5:我要充值 1.充值业务流程图 2.充值业务流程逻辑 3.数据库表 4.前端逻辑代码 5.汇付宝代码逻辑 6.尚融宝代码逻辑 7.幂等性判断原理和解决方案 8.代码规范和原理了解 核心业务5:我要充值 1.充值业务流程图

基于springboot的在线考试系统源码数据库论文

目 录 目 录 第一章 概述 1.1研究背景 1.2 开发意义 1.3 研究现状 1.4 研究内容 1.5论文结构 第二章 开发技术介绍 2.1 系统开发平台 2.2 平台开发相关技术 2.2.1 Java技术 2.2.2 mysql数据库介绍 2.2.3 MySQL环境配置 2.2.4 B/S架构 2.2.5 Spr…

如何在Linux系统中使用 envsubst 命令替换环境变量?

在Linux系统中,环境变量是非常常见的一种机制,它们被用于存储重要的系统信息,比如用户的登录名、路径等等。当在脚本中需要使用这些变量时,可以使用envsubst命令,该命令可以将环境变量的值替换到文本文件中。 本文将介…

低静态电流-汽车电池反向保护系统的方法

低静态电流-汽车电池反向保护系统的方法 背景 车辆中电子电路数量不断增加,使得需要消耗的电池电量也随之大幅增长。为了支持遥控免钥进入和安全等功能,即使在汽车停车或熄火时,电池也要持续供电。 由于所有车辆都使用有限的电池供电&…

三轴XYZ平台生成gcode文件

1. 生成gcode坐标文件 gcode文件中保存的是需要绘制图形的路径信息,这里我们采用开源矢量图形编辑软件 Inkscape并通过Unicorn G-Code插件来生成 gcode坐标文件。 将软件资料包\Inkscape.rar 压缩文件解压到电脑上任意磁盘,软件内已安装 Unicorn G-Code插…

【花雕学AI】深度挖掘ChatGPT角色扮演的一个案例—CHARACTER play : 莎士比亚

CHARACTER play : 莎士比亚 : 52岁,男性,剧作家,诗人,喜欢文学,戏剧,爱情 : 1、问他为什么写《罗密欧与朱丽叶》 AI: 你好,我是莎士比亚,一位英国的剧作家和诗人。我很高兴你对我的…

【论文速览】图像分割领域的通用大模型SegGPT - Segmenting Everything in Context

文章目录研究背景解决思路PainterSegGPT实验效果(部分)思考参考资料代码地址:https://github.com/baaivision/Painter Demo地址:https://huggingface.co/spaces/BAAI/SegGPT 研究背景 图像分割一直是计算机视觉领域的一项基础研究…

Free container identify , CIMCAI container detect cloud service

集装箱箱号识别API免费,中国上海人工智能企业CIMCAI飞瞳引擎™集装箱人工智能平台全球近4千企业用户,全球领先的飞瞳引擎™AI集装箱识别云服务,集装箱残损识别箱况检测缺陷检验,小程序拍照检测或支持API接口二次开发,应…

数据结构初阶(算法的复杂度 + 包装类 + 泛型)

文章目录一、算法复杂度1. 算法效率2. 时间复杂度(1) O的渐进表示法3. 空间复杂度二、包装2.1 为什么会出现包装2.2 分类2.3 装箱和拆箱(1)装箱/装包(2)拆箱/拆箱三、泛型3.1 泛型的基本概念3.2 泛型的使用…

2023 年 3 月 GameFi 月度报告

作者:danielfootprint.network 数据来源:Monthly GameFi Report 三月的 GameFi 世界相对沉寂,没有重大的消息公开,没有亮眼的游戏出现,也没有死亡螺旋的发生。 GameFi 领域的重要名字 Splinterlands 和 Hive 开始面…