当前位置: 首页 > news >正文

设计模式(四):建造者模式的详细解析

如果大家对java架构相关感兴趣,可以关注下面公众号,会持续更新java基础面试题, netty, spring boot,spring cloud等系列文章,一系列干货随时送达, 超神之路从此展开, BTAJ不再是梦想!

架构殿堂

概述

建造者模式属于创建型设计模式,它主要是将一个复杂对象的构建与表示分离,使用多个简单的对象一步一步构建成一个复杂的对象,它提供了一种创建对象的最佳方式。

建造者模式将复杂产品的构建过程封装在不同的方法中,使得创建过程非常清晰,能够让我们更加精确的控制复杂产品对象的创建过程,同时它隔离了复杂产品对象的创建和使用,使得相同的创建过程能够创建不同的产品。

但是如果某个产品的内部结构过于复杂,将会导致整个系统变得非常庞大,不利于控制,同时若干个产品之间存在较大的差异,则不适用建造者模式。其UML结构图如下:

在这里插入图片描述

1、定义:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示
2、主要作用:在用户不知道对象的建造过程和细节的情况下就可以直接创建复杂的对象。
3、如何使用:用户只需要给出指定复杂对象的类型和内容,建造者模式负责按顺序创建复杂对象(把内部的建造过程和细节隐藏起来)
4、解决的问题
(1)、方便用户创建复杂的对象(不需要知道实现过程)
(2)、代码复用性 & 封装性(将对象构建过程和细节进行封装 & 复用)
5、注意事项:与工厂模式的区别是:建造者模式更加关注与零件装配的顺序,一般用来创建更为复杂的对象

四个角色

  • Product(产品对象):一个具体的产品对象
  • Bulider(抽象建造者):创建一个Product对象的各个部件指定的 接口/抽象类 。指定建造流程
  • ConcreteBulider(具体建造者):实现接口,构建和装配各个部件
  • Director(指挥者):构建一个使用Bulider接口的对象,它主要是用于创建一个复杂的对象,它隔离了客户和对象的生产过程,还负责控制整个产品对象的生产过程

示例

Product

public class Product
{
    private String partA; //可以是任意类型

    private String partB;

    private String partC;

    public String getPartA()
    {
        return partA;
    }

    public void setPartA(String partA)
    {
        this.partA = partA;
    }

    public String getPartB()
    {
        return partB;
    }

    public void setPartB(String partB)
    {
        this.partB = partB;
    }

    public String getPartC()
    {
        return partC;
    }

    public void setPartC(String partC)
    {
        this.partC = partC;
    }

    @Override
    public String toString()
    {
        return "Product [partA=" + partA + ", partB=" + partB + ", partC=" + partC + "]";
    }
}

Builder

public abstract class Builder {

    protected Product product = new Product();

    public abstract void buildPartA();

    public abstract void buildPartB();

    public abstract void buildPartC();

    public Product getResult()
    {
        return product;
    }
}

ConcreteBuilder

public class ConcreteBuilder extends Builder {

    @Override
    public void buildPartA()
    {
        product.setPartA("A产品");
        System.out.println("创建A产品...");
    }

    @Override
    public void buildPartB()
    {
        product.setPartB("B产品");
        System.out.println("创建B产品...");
    }

    @Override
    public void buildPartC()
    {
        product.setPartC("C产品");
        System.out.println("创建C产品...");
    }
}

Director

public class Director {
    private Builder builder;

    //1 构造方法的方式注入builder对象
    public Director(Builder builder)
    {
        this.builder = builder;
    }

    //2 set方法注入builder对象
    public void setBuilder(Builder builder)
    {
        this.builder = builder;
    }

    public Product construct()
    {
        builder.buildPartA();
        builder.buildPartB();
        builder.buildPartC();
        return builder.getResult();
    }
}

BuilderPatternDemo

public class BuilderPatternDemo {
    public static void main(String[] args)
    {
        Builder builder = new ConcreteBuilder();
        Director director = new Director(builder);
        Product product = director.construct();
        System.out.println(product);
    }
}

输出

创建A产品...
创建B产品...
创建C产品...
Product [partA=A产品, partB=B产品, partC=C产品]

优点

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

缺点

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

应用场景

  1. 当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式时。

  2. 当复杂对象的部件相对稳定,不会发生变化时。

建造者模式与抽象工厂模式的比较

  • 与抽象工厂模式相比,建造者模式返回一个组装好的完整产品,而抽象工厂模式返回一系列相关的产品,这些产品位于不同的产品等级结构,构成了一个产品族 。
  • 在抽象工厂模式中,客户端实例化工厂类,然后调用工厂方法获取所需产品对象,而在建造者模式中,客户端可以不直接调用建造者的相关方法,而是通过指挥者类来指导如何生成对象,包括对象的组装过程和建造步骤,它侧重于一步步构造一个复杂对象,返回一个完整的对象 。
  • 如果将抽象工厂模式看成汽车配件生产工厂,生产一个产品族的产品,那么建造者模式就是一个汽车组装工厂,通过对部件的组装可以返回一辆完整的汽车.

如果大家对java架构相关感兴趣,可以关注下面公众号,会持续更新java基础面试题, netty, spring boot,spring cloud等系列文章,一系列干货随时送达, 超神之路从此展开, BTAJ不再是梦想!

架构殿堂

相关文章:

  • [swust1745] 餐巾计划问题(费用流)
  • 详尽Netty(二):源码环境搭建
  • AssetBundle管理机制(上)
  • 详尽Netty(三):Channel
  • 循序渐进之Spring AOP(5) - 创建切面
  • 牛逼!阿里推出国产开源的jdk! 快来试试吧!
  • ES6 中的let 声明变量
  • 原来Java类的加载过程是这样的?
  • 淘宝数据库OceanBase SQL编译器部分 源代码阅读--生成物理查询计划
  • 聊聊jvm几种垃圾收集器
  • 搭建 webpack + React 开发环境
  • jvm垃圾回收的过程
  • 到底什么是分布式锁,进程锁,线程锁
  • 晶振參数校定
  • 这样做能让nginx新能提升10倍
  • 【译】React性能工程(下) -- 深入研究React性能调试
  • 4月23日世界读书日 网络营销论坛推荐《正在爆发的营销革命》
  • css属性的继承、初识值、计算值、当前值、应用值
  • ES6语法详解(一)
  • learning koa2.x
  • react-core-image-upload 一款轻量级图片上传裁剪插件
  • RxJS: 简单入门
  • Shell编程
  • Transformer-XL: Unleashing the Potential of Attention Models
  • VUE es6技巧写法(持续更新中~~~)
  • vue从创建到完整的饿了么(11)组件的使用(svg图标及watch的简单使用)
  • 阿里云爬虫风险管理产品商业化,为云端流量保驾护航
  • 从零开始的webpack生活-0x009:FilesLoader装载文件
  • 短视频宝贝=慢?阿里巴巴工程师这样秒开短视频
  • 高度不固定时垂直居中
  • 快速构建spring-cloud+sleuth+rabbit+ zipkin+es+kibana+grafana日志跟踪平台
  • 体验javascript之美-第五课 匿名函数自执行和闭包是一回事儿吗?
  • 突破自己的技术思维
  • 源码安装memcached和php memcache扩展
  • ​DB-Engines 12月数据库排名: PostgreSQL有望获得「2020年度数据库」荣誉?
  • ​LeetCode解法汇总2583. 二叉树中的第 K 大层和
  • ​七周四次课(5月9日)iptables filter表案例、iptables nat表应用
  • ​一、什么是射频识别?二、射频识别系统组成及工作原理三、射频识别系统分类四、RFID与物联网​
  • #QT(智能家居界面-界面切换)
  • (1综述)从零开始的嵌入式图像图像处理(PI+QT+OpenCV)实战演练
  • (4.10~4.16)
  • (7)STL算法之交换赋值
  • (echarts)echarts使用时重新加载数据之前的数据存留在图上的问题
  • (附源码)ssm码农论坛 毕业设计 231126
  • (过滤器)Filter和(监听器)listener
  • (亲测有效)解决windows11无法使用1500000波特率的问题
  • (转)Java socket中关闭IO流后,发生什么事?(以关闭输出流为例) .
  • (转)清华学霸演讲稿:永远不要说你已经尽力了
  • (状压dp)uva 10817 Headmaster's Headache
  • (最全解法)输入一个整数,输出该数二进制表示中1的个数。
  • .helper勒索病毒的最新威胁:如何恢复您的数据?
  • .java 指数平滑_转载:二次指数平滑法求预测值的Java代码
  • .NET Core跨平台微服务学习资源
  • .net Stream篇(六)
  • .NET 中小心嵌套等待的 Task,它可能会耗尽你线程池的现有资源,出现类似死锁的情况