设计模式之建造者模式


前言

建造者模式,又称生成器模式,属于创建者模式其中的一种,除此之外还有工厂模式、单例模式、原型模式都属于创建者模式,即他们都为对象/组件的创建提供方便和扩展。

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.建造者模式适用场景
  • 相同的方法,不同的执行顺序,产生的事件结果不同
  • 多个部件一起工作,都可以装配到一个对象中,但是实际生产运行时有会产生不同,比如其中个别的部件工作
  • 产品类比较复杂,产品类中的调用顺序不同产生了不同的效能

最后引一张图片来体会一下建造者模式
在这里插入图片描述
图片来源:百度图库

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值