什么是建造者模式?
建造者模式是一种软件设计模式,它用于将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。建造者模式通常用于创建复杂对象,它包含多个部分,每个部分可以有不同的组成方式。
需求
一个类计算机类Computer包括以下变量
- cpu
- ram
- usbCount
- keyboard
- display
而其他3个是可选参数
- usbCount
- keyboard
- display
两种常用的方式
折叠构造器模式
Javabean 直接定义
缺点
第1种
第一种主要是使用及阅读不方便。当调用一个类的构造函数时,
首先要决定使用哪一个,里面参数又很多,参数的类型也不一样,
这样很容易搞混
第2种
在构建过程中对象的状态容易发生变化,造成错误。
因为那个类中的属性是分步设置的,所以就容易出错。
特点
在软件开发过程中有时需要创建一个复杂的对象,这个复杂对象通常由多个子部件按一定的步骤组合而成。
产品都是由多个部件构成的,各个部件可以灵活选择,但其创建步骤都大同小异。
这类产品的创建无法用前面介绍的工厂模式描述,只有建造者模式可以很好地描述该类产品的创建。
建造者模式解决需求(代码实现)
第一步:创建目标类, 也就是我们的产品
/** * 产品 计算机 * * @author yang shuai * @date 2022/12/4 */ public class Computer { private final String cpu;// 必须 private final String ram;// 必须 private int usbCount;// 可选 private String keyboard;// 可选 private String display;// 可选 public Computer(String cpu, String ram) { this.cpu = cpu; this.ram = ram; } public void setUsbCount(int usbCount) { this.usbCount = usbCount; } public void setKeyboard(String keyboard) { this.keyboard = keyboard; } public void setDisplay(String display) { this.display = display; } @Override public String toString() { return "Computer{" + "cpu='" + cpu + '\'' + ", ram='" + ram + '\'' + ", usbCount=" + usbCount + ", keyboard='" + keyboard + '\'' + ", display='" + display + '\'' + '}'; } }
第二步:创建抽象构建者类
public abstract class ComputerBuilder { public abstract void buildCount(int usbCount); public abstract void buildKeyboard(String keyBoard); public abstract void buildDisplay(String display); public abstract Computer makeComputer(); }
第三步:创建具体建造者类
public class HWComputerBuilder extends ComputerBuilder{ private Computer computer; public HWComputerBuilder(String cpu, String ram) { computer=new Computer(cpu,ram); } @Override public void buildCount(int usbCount) { computer.setUsbCount(usbCount); } @Override public void buildKeyboard(String keyBoard) { computer.setKeyboard(keyBoard); } @Override public void buildDisplay(String display) { computer.setDisplay(display); } @Override public Computer makeComputer() { return computer; } }
第四步:创建指挥类
public class ComputerDirector { private ComputerBuilder builder; public void setBuilder(ComputerBuilder builder) { this.builder = builder; } public Computer makeComputer(int useCount,String display,String keyBoard){ builder.buildCount(useCount); builder.buildDisplay(display); builder.buildKeyboard(keyBoard); return builder.makeComputer(); } }
定义
指将一个复杂对象的构造与它的表示分离,使同样的构建过程可以创建不同的表示,这样的设计模式被称为建造者模式。
它是将一个复杂的对象分解为多个简单的对象,然后一步一步构建而成。即产品的组成部分是不变的,但每一部分是可以灵活选择的。
建造者模式与工厂模式的区别
工厂模式
- 工厂模式注重于创建产品
- 工厂模式创建出来的产品都是一个样子
- 工厂模式的关注点是只要创建出对象就可以了
建造者模式
- 建造者模式注重于方法的调用顺序
- 建造者模式可以创建出复杂的产品,由各种复杂的部件组成
- 建造者模式不仅要创建产品,,还要知道该产品是由哪些部件组成的
建造者模式包括四个角色:
- Product(产品角色):一个具体的产品对象。
- Builder(抽象建造者):创建一个Product对象的各个部件指定的接口/抽象类。
- ConcreteBuilder(具体建造者):实现接口,构建和装配各个部件。
- Director(指挥者):构建一个使用Builder接口的对象。
它主要是用于创建一个复杂的对象。
作用
隔离了客户与对象的生产过程
负责控制产品对象的生产过程。
建造者模式的优点有:
- 它隔离了具体组建和装配方式,使得构建过程与具体实现分离。
- 它支持构建复杂对象,并且可以控制复杂对象的构建顺序。
- 它可以使得用户可以独立地改变一个对象的内部表示。
- 它可以提供一种灵活的构建方式,在用户不确定最终的产品的具体细节时也可以创建对象。
- 它可以有效地防止用户在构建过程中破坏产品的结构。
大白话:
封装性好,构建和表示分离。
扩展性好,各个具体的建造者相互独立,有利于系统的解耦。
客户端不必知道产品内部组成的细节,建造者可以对创建过程逐步细化,而不对其它模块产生任何影响,便于控制细节风险。
建造者模式的缺点有:
- 产生多余的Builder对象
- 产品内部发生变化,建造者都要修改,成本较大
建造者模式第二种写法
解决产生多余的Builder对象等
在Computer 中创建一个静态内部类 Builder,然后将Computer 中的参数都复制到Builder类中。
示例:
/** * 使用静态内部类构造数据 * * @author yang shuai * @date 2022/12/9 */ public class Computer { private final String cpu;//必须 private final String ram;//必须 private final int usbCount;//可选 private final String keyboard;//可选 private final String display;//可选 @Override public String toString() { return "Computer{" + "cpu='" + cpu + '\'' + ", ram='" + ram + '\'' + ", usbCount=" + usbCount + ", keyboard='" + keyboard + '\'' + ", display='" + display + '\'' + '}'; } private Computer(Builder computerBuilder) { this.cpu = computerBuilder.cpu; this.ram = computerBuilder.ram; this.usbCount = computerBuilder.usbCount; this.keyboard = computerBuilder.keyboard; this.display = computerBuilder.display; } public static class Builder { private final String cpu;//必须 private final String ram;//必须 private int usbCount;//可选 private String keyboard;//可选 private String display;//可选 public Builder(String cup, String ram) { this.cpu = cup; this.ram = ram; } public Builder buildUsbCount(int usbCount) { this.usbCount = usbCount; return this; } public Builder buildKeyboard(String keyboard) { this.keyboard = keyboard; return this; } public Builder buildDisplay(String display) { this.display = display; return this; } public Computer build() { return new Computer(this); } } }
使用场景
如果一个对象有非常复杂的内部结构(很多属性)
想把复杂对象的创建和使用分离
总结
用来创建复杂的复合对象
源码分析
StringBuilder
- JDK 的 StringBuilder 类中提供了 append() 方法,这就是一种链式创建对象的方法,开放构造步骤,最后调用 toString() 方法就可以获得一个完整的对象
SqlSessionFactoryBuilder
- MyBatis 中 SqlSessionFactoryBuiler 类用到了建造者模式。且在 MyBatis 中 SqlSessionFactory是由 SqlSessionFactoryBuilder 产生的
- XMLConfigBuilder 负责 Configuration 各个组件的创建和装配,整个装配的流程化过程如下:
- XMLConfigBuilder 负责创建复杂对象 Configuration,其实就是一个具体建造者角色。
- SqlSessionFactoryBuilder 只不过是做了一层封装去构建 SqlSessionFactory 实例,这就是建造者模式简化构建的过程。