什么是建造者模式?

2023-05-16

为什么会有这个模式?

很多时候我们会构建非常复杂的类,内部初始化构成需要进行很多复杂交互操作,比如需要去数据库查询数据后作为属性初始值,或者说我们想控制它的内部初始化的过程,将构建过程分离出来。

1 简介

1.1 什么是建造者模式

建造者模式是创建模式之一,看到“建造”就明白这肯定是个不断累加的过程,比如说你想自己装一台笔记本,那你得装cpu、内存、硬盘、显卡、散热…需要很多东西来支持最后这个产品的完成,并且在组装过程中每一步要有一定的顺序,如果组装配件的品质不一样,最后得到的产品也会不一样。
简单来说就是通过一切些方式(继承、重载),动态创建具有多种属性的对象。

1.2 应用场景

上面介绍已经说过了,就是在构建复杂对象的时候,比如持有数据的对象,或者内部数据需要以一定顺序加载的时候。让构建的过程透明,使用者运行很少的代码就能创建一个十分复杂的对象。

2 原理

2.1 UML类图

在这里插入图片描述

2.2 模式分析

懂了吧。。。

  • 产品经理和客户打交道明白具体需求,他也不需要明白具体实现,只要最后结果差不多就行
  • 技术经理就在框架方法上进行把控,把任务分给下面的许多程序员
  • 不同程序员负责产品不同部分的具体实现
  • 不同的构建情况组合成不同的具体产品

3 具体实例

我们假设要生产一台“电脑”,请翻到计算机组成原理第一节,大声告诉我冯·诺依曼计算机由哪几部分组成?时隔几年还是忘不了大学时光呀

我们先看看咱们要做一个什么样的产品

/**
 * what:    这是咱们的计算机 <br/>
 * how:     (如何使用). <br/>
 *
 * @author ycf created on 2020/7/13
 */
public class Computer {
    //运算器
    private Calculator calculator;
    //控制器
    private Controller controller;
    //存储器
    private Storage storage;
    //操作系统
    private Os os;
    //输入输出设备
    private InputOutput io;

    public Calculator getCalculator() {
        return calculator;
    }

    public void setCalculator(Calculator calculator) {
        this.calculator = calculator;
    }

    public Controller getController() {
        return controller;
    }

    public void setController(Controller controller) {
        this.controller = controller;
    }

    public Storage getStorage() {
        return storage;
    }

    public void setStorage(Storage storage) {
        this.storage = storage;
    }

    public Os getOs() {
        return os;
    }

    public void setOs(Os os) {
        this.os = os;
    }

    public InputOutput getIo() {
        return io;
    }

    public void setIo(InputOutput io) {
        this.io = io;
    }
}

代码里Calculator、Controller …等类都是自己创建的,里面没什么方法,只是做标识,完整代码我已经上传了,下文里有链接

首先我们需要定义一个Builder,其实可以抽象类也可以接口,这个类定义了所有具体建造者应该做哪些事情

/**
 * what:   建造者,咱们的技术经理<br/>
 * how:     (如何使用). <br/>
 *
 * @author ycf created on 2020/7/13
 */
public abstract class AbstractBuilder {
	//构建运算器
    abstract void buildCalculator();
    //构建控制器
    abstract void buildController();
    //构建输入输出设备
    abstract void buildInputOutput();
    //构建操作系统
    abstract void buildOs();
    //构造存储器
    abstract void buildStorage();
    //生产电脑
    abstract Computer createComputer();
}

然后我们要创建具体的Builder来生产咱们的产品,这里为了举例我写了两个builder,一个用来生产联想电脑,一个用来生产mac

/**
 * what:    咱们组装一台联想电脑. <br/>
 * how:     (如何使用). <br/>
 *
 * @author ycf created on 2020/7/13
 */
public class LenovoBuilder extends AbstractBuilder{

    private Computer lenovoComputer = new Computer();

    @Override
    void buildCalculator() {
        lenovoComputer.setCalculator(new LenovoCalculator());
    }

    @Override
    void buildController() {
        lenovoComputer.setController(new LenovoController());
    }

    @Override
    void buildInputOutput() {
        lenovoComputer.setIo(new LenovoIo());
    }

    @Override
    void buildOs() {
        lenovoComputer.setOs(new LenovoOs());
    }

    @Override
    void buildStorage() {
        lenovoComputer.setStorage(new LenovoStorage());

    }

    @Override
    Computer createComputer() {
        return lenovoComputer;
    }
}


/**
 * what:    咱们组装一台Mac. <br/>
 * how:     (如何使用). <br/>
 *
 * @author ycf created on 2020/7/13
 */
public class MacBuilder extends AbstractBuilder{

    private Computer macComputer = new Computer();

    @Override
    void buildCalculator() {
        macComputer.setCalculator(new MacCalculator());
    }

    @Override
    void buildController() {
        macComputer.setController(new MacController());
    }

    @Override
    void buildInputOutput() {
        macComputer.setIo(new MacIo());
    }

    @Override
    void buildOs() {
        macComputer.setOs(new MacOs());
    }

    @Override
    void buildStorage() {
        macComputer.setStorage(new MacStorage());

    }

    @Override
    Computer createComputer() {
        return macComputer;
    }
}

可以看到上面两个具体builder类在实现抽象方法时调用了不同的组件来构建产品,即实际生产的是哪一种产品取决于是哪个具体builder在构建产品,我们还需要一个Director来和用户(client)沟通

/**
 * what:    产品经理开始忽悠客户了 <br/>
 * how:     (如何使用). <br/>
 *
 * @author ycf created on 2020/7/13
 */
public class Director {
    private AbstractBuilder builder = null;

    public Director(AbstractBuilder builder){
    	//指定当前实际builder
        this.builder = builder;
    }

    public Computer createComputer(){
    	//组装电脑
        builder.buildCalculator();
        builder.buildController();
        builder.buildInputOutput();
        builder.buildOs();
        builder.buildStorage();
		//生产电脑
        return builder.createComputer();
    }

}

OK,现在顾客可以通过产品经理(Director)来或者指定产品了:

/**
 * what:    客户要买电脑了,肯定找咱们产品经理呀 <br/>
 * how:     (如何使用). <br/>
 *
 * @author ycf created on 2020/7/13
 */
public class Client {
    public static void main(String[] args) {
        //先来一台联想的
        Computer lenovoComputer =  buyComputer(new LenovoBuilder());

        //再来一台Mac
        Computer macComputer = buyComputer(new MacBuilder());

    }

    private static Computer buyComputer(AbstractBuilder builder){
        Director director = new Director(builder);
        return director.createComputer();
    }
}

点击获取完整代码
提取码: 5qce

除了上述用法之外,建造者模式还常用于优化构造函数参数过多,可读性不高的情况。优化前:

/**
 * what:   多参数优化演示 <br/>
 * how:     (如何使用). <br/>
 *
 * @author ycf created on 2020/7/13
 */
public class Computer {

    private String calculator;
    private String controller;
    private String inputoutput;
    private String os;
    private String storage;

    private Computer(){
    }

    Computer(String calculator,String controller,String inputoutput,String os,String storage){
        this.calculator = calculator;
        this.controller = controller;
        this.inputoutput = inputoutput;
        this.os = os;
        this.storage = storage;
    }
}

我们再来看看优化后:

/**
 * what:    优化后 <br/>
 * how:     (如何使用). <br/>
 *
 * @author ycf created on 2020/7/13
 */
public class ComputerPlus {
    private String calculator;
    private String controller;
    private String inputoutput;
    private String os;
    private String storage;

    private ComputerPlus(){
    }

    public final static class  Builder{
        private String calculator;
        private String controller;
        private String inputoutput;
        private String os;
        private String storage;

        public Builder(){

        }

        public Builder calculator(String calculator){
            this.calculator = calculator;
            return this;
        }
        public Builder controller(String controller){
            this.controller = controller;
            return this;
        }
        public Builder inputoutput(String inputoutput){
            this.inputoutput = inputoutput;
            return this;
        }
        public Builder os(String os){
            this.os = os;
            return this;
        }
        public Builder storage(String storage){
            this.storage = storage;
            return this;
        }
        public ComputerPlus createComputerPlus(){
            return new ComputerPlus(this);
        }
    }
}

利用静态内部类来存储配置并组装目标对象,会让代码可读性提高不少,下面来看看使用时的差别:

/**
 * what:    优化测试. <br/>
 * how:     (如何使用). <br/>
 *
 * @author ycf created on 2020/7/13
 */
public class Test {
    public static void main(String[] args) {

        //优化前
        Computer computer = new Computer("1","2","3","4","5");

        //优化后可读性大大提高
        ComputerPlus computerPlus = new ComputerPlus.Builder()
                .calculator("1")
                .controller("2")
                .inputoutput("3")
                .os("4")
                .storage("5")
                .createComputerPlus();
    }
}

是不是显得优雅多了 ?
当然建造者模式缺点也显而易见,和抽象工厂一样的代码膨胀问题,不过这也算是牺牲空间换取时间了吧。并且在拓展性上不如抽象工厂,要求创建的产品的相似性比较高的时候使用。

好的,对建造者模式的讲解就到这里了,如有错误欢迎指正!O(∩_∩)O

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

什么是建造者模式? 的相关文章

  • Spring Boot and OAuth2翻译

    Spring Boot and OAuth2 本指南将向您展示如何使用OAuth2和Spring Boot构建一个使用 社交登录 功能做各种事情的应用程序示例 它从一个简单的单一提供者单点登录开始 xff0c 并运行一个带有身份验证提供程序
  • 实现线程安全的常见手段

    Thread safety 线程安全是我们设计一个类是必须考虑的问题 xff0c 在一些常用的工具类库上 xff0c 是否线程安全也会作为一个很重要的标注告诉使用者 常见的实现线程安全的手段有哪些呢 xff1f 无状态 即 xff0c 将接
  • 【ROM定制】Android 12 制作『MIUI官改』那点事④修改

    作者 xff1a 小谢 内容 xff1a MIUI官改 的修改 时间 xff1a 2022 10 14 机型 xff1a 小米10 安卓 xff1a Android 12 版本 xff1a V13 0 7 0稳定版 制作 MIUI官改 工具
  • ubuntu(17):ubuntu循环登录/无法进入图形化界面解决方法--因为系统内核版本冲突/不合适

    1 问题排查 2 查找合适内核 3 删除多余内核版本 删除启动项 3 1 删除内核 3 2 删除启动项 这一步没起作用 3 3 修改默认启动内核 参考链接 xff1a 1 问题排查 昨天重装了nvidia显卡驱动 开机后一直循环登录 xff
  • Android Studio targetApi=33 android 13 setAppCacheEnabled/setAppCachePath/setAppCacheMaxSize 报红问题探究

    报红如下 可以看到即使加了Api版本判断依然是报红的 编译后有如下类似错误提示 Launching lib main dart on sdk gphone64 arm64 in debug mode Users dararii Dev fl
  • MATLAB自适应中值滤波代码

    最近数字图像处理课程课后作业 xff0c 要求自己用代码实现自适应中值滤波器 xff0c 虽然很简单 xff0c 但是在网上找了一圈也没有可以直接拿来用的 xff0c 所以就在网上找了一段代码 xff0c 并且自己改了一下 xff0c 能够
  • VNC连接超时

    一 bug截图 二 原因分析 远程连接 远程连接是要提供地址的 xff0c 这里的地址是IP 43 桌面号 xff0c 比如 xff1a 192 168 1 23 2 随后提示你输入密码 xff0c 此密码就是刚才第1个步骤这是的密码 一般
  • WebApi 异常处理解决方案

    C 进阶系列 WebApi 异常处理解决方案 前端开发 waitig 1年前 2017 04 14 238 百度已收录 0评论 阅读目录 一 使用异常筛选器捕获所有异常 二 HttpResponseException自定义异常信息 三 返回
  • springboot applicaton.properties配置多种数据源

    html view plain copy print DB Connection Config DB Type the database of the application mysql sqlserver oracle databaseT
  • SpringBoot项目在IntelliJ IDEA中实现热部署

    spring boot devtools是一个为开发者服务的一个模块 xff0c 其中最重要的功能就是自动应用代码更改到最新的App上面去 原理是在发现代码有更改之后 xff0c 重新启动应用 xff0c 但是速度比手动停止后再启动更快 其
  • Spring Boot集成webService

    服务端 使用idea创建spring boot工程 xff1a File New Project Spring Initializr 在pom添加依赖 span class hljs tag span class hljs tag lt s
  • spring boot整合OAuth2保证api接口安全

    1 OAuth 概念 OAuth 是一个开放标准 xff0c 允许用户让第三方应用访问该用户在某一网站上存储的私密的资源 xff08 如照片 xff0c 视频 xff0c 联系人列表 xff09 xff0c 而不需要将用户名和密码提供给第三
  • 软件项目的开发流程

    一个软件开发项目过程 xff1a 1 项目启动 1 项目组成立 公司成员 客户成员 2 制定项目预期目标 3 制定项目计划周期 4 建立好项目组成员沟通机制 2 需求调研 1 创建调研计划 协调调研时间 2 收集客户资料 xff0c 获取客
  • asp、jsp与html+ajax优缺比较

    我对jsp和ajax 一直比较困惑 xff0c jsp动态网页技术 xff0c 在服务器端执行 xff0c 能在网页中显示数据这是一种方式 另一种方式是 我打开一个网页 xff08 html xff09 xff0c 加载完成之后 xff0c
  • < Linux > 多线程(生产者消费者模型)

    目录 1 生产者消费者模型 生产者消费者模型的例子 生产者消费者模型的特点 生产者消费者模型的优点 2 基于BlockingQueue的生产者消费者模型 概念 模拟实现基于阻塞队列的生产消费模型 基于计算任务的生产者消费者模型 xff08
  • 分布式秒杀系统限流

    前言 俗话说的好 xff0c 冰冻三尺非一日之寒 xff0c 滴水穿石非一日之功 xff0c 罗马也不是一天就建成的 两周前秒杀案例初步成型 xff0c 分享到了中国最大的同性交友网站 码云 同时也收到了不少小伙伴的建议和投诉 我从不认为分
  • centos下使用docker安装tomcat部署Javaweb项目

    主要步骤 安装docker 卸载旧版本docker 如果centos系统中存在老版本的docker xff0c 可以先卸载掉旧版本的docker xff0c 再安装新版本docker yum remove docker docker com
  • Dockerfile指令介绍

    Docker通过对于在Dockerfile中的一系列指令的顺序解析实现自动的image的构建 通过使用build命令 xff0c 根据Dockerfiel的描述来构建镜像 通过源代码路径的方式 通过标准输入流的方式 通过源代码路径 Dock
  • redis面试知识点

    Redis在互联网技术存储方面使用如此广泛 xff0c 几乎所有的后端技术面试官都要在Redis的使用和原理方面对小伙伴们进行各种刁难 作为一名在互联网技术行业打击过成百上千名 请允许我夸张一下 的资深技术面试官 xff0c 看过了无数落寞

随机推荐

  • Redis分布式锁

    前言 分布式锁一般有三种实现方式 xff1a 1 数据库乐观锁 xff1b 2 基于Redis的分布式锁 xff1b 3 基于ZooKeeper的分布式锁 本篇博客将介绍第二种方式 xff0c 基于Redis实现分布式锁 虽然网上已经有各种
  • SpringCloud全套教程

    https gitee com didispace SpringCloud Learning
  • docker远程连接配置

    在开发的时候 xff0c 我们进程需要用到docker 但很多时候我们用的是window作为开发平台 xff0c 虽然Docker也有window版本的 但window的DockerToolbox是一款不是很成熟的产品 xff0c 有很多小
  • 单相逆变器及基于STM32 SPWM生成代码

    2022 4 26更新 若需商业合作可私聊留VX号 xff0c 博主看到后会添加的 最近在做单相逆变器 xff0c 用篇文章来记录 主电路采用H桥 xff0c 使用IR2104半桥驱动内置630ns死区 xff0c 上管采用自举电容浮地驱动
  • 20200329 百度 测试开发实习 笔试题

    20200329 百度 测试开发实习 笔试题 第一题题目描述 xff1a 输入输出样例输入样例输出提示 第二题题目描述 xff1a 输入输出样例输入样例输出 第一题 题目描述 xff1a 桌子上放着N枚硬币 xff0c 将其从1到N编号 x
  • 《Linux就该这么学》第1章 部署虚拟环境安装Linux系统

    Linux就该这么学 第1章 部署虚拟环境安装Linux系统 目录 常见的Linux系统版本 安装配置VM虚拟机 安装Linux系统 RPM xff08 红帽软件包管理器 xff09 Yum软件仓库 systemd初始化进程 需要长期稳定运
  • 辛勤劳作

    本文只有在12月27日可以学习到 我对敬业的体会是 xff1a 正在从事的工作就是自己的生命 xff0c 它意味着每周7天 xff0c 每年52周一心扑在上面 写下上面这句话 xff0c 我的泪水差一点儿就涌了出来 14年的寿险生涯 xff
  • RocketMQ

    1 主题中存在多个队列 xff0c 生产者向主题中指定的队列发送消息 2 在集群模式下 xff0c 一个消费者集群共同消费一个主题中的多个队列 xff0c 但一个队列只会被一个消费者消费 在广播模式下 xff0c 会被订阅主题的所有消费者消
  • 记一次Gradle搭建多模块项目遇到的问题

    前言 最开始 xff0c 我创建了一个空的项目 xff0c 并在该项目下依次创建了3个模块 但是我发现 xff0c 这几个模块引入的依赖绝大多数都是相同的 于是 xff0c 我灵光一闪 xff08 其实是在最初构建项目时的没想到 xff09
  • springboot 项目访问controller没有进入拦截器

    在项目中新写了一个校验token是否存在的拦截器之后 xff0c 编译和启动都没有问题 直到访问方法的时候发现并没有进入这个拦截器 后来发现是因为springboot在启动之后 xff0c 启动类只会扫描启动类所在的包下的方法 解决方法就是
  • leetcode 1170. 比较字符串最小字母出现频次(C++)

    我们来定义一个函数 f s xff0c 其中传入参数 s 是一个非空字符串 xff1b 该函数的功能是统计 s 中 xff08 按字典序比较 xff09 最小字母的出现频次 例如 xff0c 若 s 61 34 dcce 34 xff0c
  • maven私库nexus2.11.4迁移升级到nexus3.12.0

    https www cnblogs com liangyou666 p 9439755 html nexus简介 nexus是一个强大的maven仓库管理器 它极大的简化了本地内部仓库的维护和外部仓库的访问 nexus是一套开箱即用的系统不
  • Linux安装JDK8详细图文教程

    第一步 获取JDK文件 JDK下载包 xff1a 直接进入 如果跳转登录页面 xff0c 注册一个账号登录即可 登录过后文件就下载完成 第二步 上传JDK到服务器 1 创建JDK目录 span class token function mk
  • 购物商城shopping连载(11)

    订单模块类创建及配置 购物完成之后 xff0c 提交订单 xff0c 生成一个订单 订单表和商品的关系 xff1a 订单和商品的关系是多对多 xff0c 一个订单可以有多个商品 xff0c 一个商品可以属于多个订单 如果是多对多的关系 xf
  • CSS面试题:20道含答案和代码示例的练习题

    如何水平居中一个元素 xff1f 答案 xff1a 可以使用text align属性设置父元素的文本对齐方式为center xff0c 也可以使用margin属性设置元素的左右margin为auto 如何垂直居中一个元素 xff1f 答案
  • Ubuntu GNOME去除顶栏和窗口标题栏方法(亲测可用)

    一 环境 Ubuntu16 04 43 gnome3 gome shell 3 18 5 二 简介 因项目需要 xff0c 软件在 Ubuntu 系统中运行 xff0c 并且全屏显示 而在 Ubuntu 系统中 xff0c 侧边栏的自动隐藏
  • linux 配置FTP多个虚拟用户,私人目录+共享目录

    需求 xff1a 公司多个部门 xff0c 行政 xff0c 财务 xff0c 人事 xff0c 运营 xff0c 每个部门都能上传下载文件 xff0c pub目录是共享目录 xff0c 每个部门都可以上传下载 xff0c 但是无法删除 每
  • Java8新特性详解

    陈老老老板 说明 xff1a 新的专栏 xff0c 本专栏专门讲Java8新特性 xff0c 把平时遇到的问题与Java8的写法进行总结 xff0c 需要注意的地方都标红了 xff0c 一起加油 本文是介绍Java8新特性与常用方法 xff
  • java 基础 matches()方法的作用

    java lang包中的String类 xff0c java util regex包中的Pattern xff0c Matcher类中都有matches 方法 都与正则表达式有关 下面我分别举例 xff1a xff08 字符串 xff1a
  • 什么是建造者模式?

    为什么会有这个模式 xff1f 很多时候我们会构建非常复杂的类 xff0c 内部初始化构成需要进行很多复杂交互操作 xff0c 比如需要去数据库查询数据后作为属性初始值 xff0c 或者说我们想控制它的内部初始化的过程 xff0c 将构建过