前言
建造者模式,又称生成器模式,属于创建者模式其中的一种,除此之外还有工厂模式、单例模式、原型模式都属于创建者模式,即他们都为对象/组件的创建提供方便和扩展。
1.什么是建造者模式
个人理解是以不变的流程去组装不同形态、外观的产品,就像生产一件电子产品一样,譬如手机,一款手机的出厂都需要经过元器件采购、生产线组装、测试,这个流程可以认为是不变的,但是生产出来的具体的生产顺序或者产品配置是不同的,而建造者从表面上看就是完成类似的流程。
再或者平时我们的对象属性比较多的时候,创建对象过程就会变得繁琐,需要使用构造器或者setter方法对属性挨个赋值,而且这个过程我们必须更细致的了解对象的属性,创建对象过程和客户端代码是紧耦合的。
建造者模式为我们提供了另外一种建造对象的思路,使用建造者模式,对象的创建赋值细节全部交给建造者来完成,客户端只需要掌握基本流程即可,不需要了解对象的细节,这和工厂模式有点类似,个人觉得工厂方法更像是要创建一系列标准的对象,而建造者关注的是标准的对象创建流程。
一个传统建造者模式有如下四种角色:
1.Product:
具体的产品对象
2.AbstractBuilder:
创建一个产品对象各个部件指定的抽象类,用来规范具体的建造者方法,是多个规范相同的具体建造者的抽象,该类会声明两种类型方法,第一种类型就是构建产品每个部分(Part)的一系列操作,第二种类型则是返回真正构建完成的产品对象
3.ConcreteBuilde:
具体建造者实现类,实现具体的建造方法,一个具体的建造者对应一个具体产品
4.Director:
构建一个中间对象,用于客户端指挥建造者建造对象,隔离客户端与具体产品的生产过程,控制产品对象的生产流程
2.示例
以生产汽车为例,不同的汽车有不同的配置,用一套标准的流程去创建一些列不同配置的汽车对象
首先声明一个汽车类
/**
* @description: 产品汽车
* @version: 1.0
*/
public class Car {
/**汽车名称*/
private String name;
/**引擎*/
private String engine;
/**排量*/
private String displacement;
/**驱动类型 四驱/两区*/
private String driveType;
/**变速箱*/
private String speedBox;
/**倒车影像*/
private boolean backImage;
/**ESP系统*/
private boolean ESP;
/**ABS系统*/
private boolean ABS;
public Car(String name, String engine, String displacement) {
this.name = name;
this.engine = engine;
this.displacement = displacement;
}
public void setDriveType(String driveType) {
this.driveType = driveType;
}
public void setSpeedBox(String speedBox) {
this.speedBox = speedBox;
}
public void setBackImage(boolean backImage) {
this.backImage = backImage;
}
public void setESP(boolean ESP) {
this.ESP = ESP;
}
public void setABS(boolean ABS) {
this.ABS = ABS;
}
@Override
public String toString() {
return "Car{" +
"name='" + name + '\'' +
", engine='" + engine + '\'' +
", displacement='" + displacement + '\'' +
", driveType='" + driveType + '\'' +
", speedBox='" + speedBox + '\'' +
", backImage=" + backImage +
", ESP=" + ESP +
", ABS=" + ABS +
'}';
}
}
如果想要创建汽车对象,可以直接使用new创建汽车对象,属性赋值可以使用构造器或者setter方法,比如:
Car car = new Car("benz","ea888","2.0T");
car.setSpeedBox("Auto");
//....
通过建造者模式创建对象可以这么做,先抽象一个建造者出来,抽象类和接口都可以,可以理解为Car构造中的参数是必须要有的部件,而通过建造者设置的属性是可选部件,建造者中声明了剩余部件的设置方法,并且还需要提供一个产品产出的方法,返回值就是我们最后实际建造的产品
/**
* @description: 建造者抽象
* @version: 1.0
*/
public abstract class CarBuilder {
public abstract void setDriveType();
public abstract void setSpeedBox();
public abstract void setBackImage();
public abstract void setESP();
public abstract void setABS();
public abstract Car build();
}
接下来就是实现一个具体的建造者
/**
* @description: TODO
* @create by twotiger2tigersofast
* @datetime 2023/3/22 22:09
* @version: 1.0
*/
public class QIRuiQQCarBuilder extends CarBuilder{
private Car car;
public QIRuiQQCarBuilder(String name, String engine, String displacement){
car = new Car(name,engine,displacement);
}
@Override
public void setDriveType() {
car.setDriveType("4WD");
}
@Override
public void setSpeedBox() {
car.setSpeedBox("Auto");
}
@Override
public void setBackImage() {
car.setBackImage(true);
}
@Override
public void setESP() {
car.setESP(true);
}
@Override
public void setABS() {
car.setABS(true);
}
@Override
public Car build() {
return car;
}
}
以上实现了一个QIRuiQQCar的builder类,该类中持有了真正的car对象,该对象只是一个基础产品,只要求初始化部分必须的属性
最后我们需要一个指导者类
/**
* @description: 建造者类
* @version: 1.0
*/
public class Director {
public void produceCar(CarBuilder builder){
builder.setABS();
builder.setBackImage();
builder.setDriveType();
builder.setSpeedBox();
builder.setESP();
}
}
测试
public class Test {
public static void main(String[] args) {
CarBuilder builder = new QIRuiQQCarBuilder("奇瑞QQ4.0T双涡轮增压旗舰至尊四驱版","V8双涡轮","4.0T");
Director director = new Director();
director.produceCar(builder);
Car car = builder.build();
System.out.println(car);
}
}
以上是一个传统的建造者模式,一般情况下更多用的是他的变种,就是省略了Director这个中间指挥角色,直接将构建流程暴露给客户端,并且在每一步构建中返回this指针,从而实现了链式调用,这个还是比较常见的,比如将以上代码改造一下,产品不变,只需要修改构建者
public abstract class CarBuilder {
public abstract CarBuilder setDriveType(String driveType);
public abstract CarBuilder setSpeedBox(String speedBox);
public abstract CarBuilder setBackImage(boolean backImage);
public abstract CarBuilder setESP(boolean ESP);
public abstract CarBuilder setABS(boolean ABS);
public abstract Car build();
}
public class QIRuiQQCarBuilder extends CarBuilder{
private Car car;
public QIRuiQQCarBuilder(String name, String engine, String displacement){
car = new Car(name,engine,displacement);
}
@Override
public CarBuilder setDriveType(String driveType) {
car.setDriveType(driveType);
return this;
}
@Override
public CarBuilder setSpeedBox(String speedBox) {
car.setSpeedBox(speedBox);
return this;
}
@Override
public CarBuilder setBackImage(boolean backImage) {
car.setBackImage(backImage);
return this;
}
@Override
public CarBuilder setESP(boolean ESP) {
car.setESP(ESP);
return this;
}
@Override
public CarBuilder setABS(boolean ABS) {
car.setABS(ABS);
return this;
}
@Override
public Car build() {
return car;
}
}
测试:
public class Test {
public static void main(String[] args) {
CarBuilder builder = new QIRuiQQCarBuilder("奇瑞QQ4.0T双涡轮增压旗舰至尊四驱版","V8双涡轮","4.0T");
Car car = builder.setSpeedBox("Auto")
.setESP(true)
.setDriveType("4WD")
.setBackImage(true)
.setABS(true).build();
System.out.println(car);
}
}
亦或者,可以使用静态内部类来简化这个过程
public class Car2 {
private final String name;
private final String engine;
private final String displacement;
private final String driveType;
private final String speedBox;
private final boolean backImage;
private final boolean ESP;
private final boolean ABS;
/*
私有对象构造,外部不允许直接创建对象,必须通过静态构建器
*/
private Car2(Builder builder) {
this.name = builder.name;
this.engine = builder.engine;
this.displacement = builder.displacement;
this.driveType = builder.driveType;
this.speedBox = builder.speedBox;
this.backImage = builder.backImage;
this.ESP = builder.ESP;
this.ABS = builder.ABS;
}
public static class Builder{
private String name;
private String engine;
private String displacement;
private String driveType;
private String speedBox;
private boolean backImage;
private boolean ESP;
private boolean ABS;
public Builder (String name, String engine, String displacement ){
this.name = name;
this.engine = engine;
this.displacement = displacement;
}
public Builder setDriveType(String driveType) {
this.driveType = driveType;
return this;
}
public Builder setSpeedBox(String speedBox) {
this.speedBox = speedBox;
return this;
}
public Builder setBackImage(boolean backImage) {
this.backImage = backImage;
return this;
}
public Builder setESP(boolean ESP) {
this.ESP = ESP;
return this;
}
public Builder setABS(boolean ABS) {
this.ABS = ABS;
return this;
}
public Car2 build(){
return new Car2(this);
}
}
@Override
public String toString() {
return "Car2{" +
"name='" + name + '\'' +
", engine='" + engine + '\'' +
", displacement='" + displacement + '\'' +
", driveType='" + driveType + '\'' +
", speedBox='" + speedBox + '\'' +
", backImage=" + backImage +
", ESP=" + ESP +
", ABS=" + ABS +
'}';
}
}
3.建造者模式适用场景
- 相同的方法,不同的执行顺序,产生的事件结果不同
- 多个部件一起工作,都可以装配到一个对象中,但是实际生产运行时有会产生不同,比如其中个别的部件工作
- 产品类比较复杂,产品类中的调用顺序不同产生了不同的效能
最后引一张图片来体会一下建造者模式
图片来源:百度图库