创建型模式——建造者模式

一、介绍

建造者模式、创建者模式、生成器模式,想叫什么就叫什么,它是将一个复杂的对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。创建者模式屏蔽了复杂对象的创建过程,它把复杂对象的创建过程加以抽象,通过子类继承或者重载的方式,动态的创建具有复合属性的对象。看懂概念,是高手,看不懂也没瓜西,看后面的案例。

二、角色说明

  • 产品角色:一个具体的产品对象
  • 抽象建造者:创建一个产品类对象的各个部件指定的接口或抽象类
  • 具体建造者:实现接口,构建和装配各个部件
  • 指挥者:构建一个使用建造者接口的对象,主要用于创建一个复杂的对象,在这个过程中,发挥的作用有两个: a、隔离了客户与对象的生产过程,b、负责控制产品对象的生产过程

三、案例——不用建造者模式,用传统方式实现造车需求

需求:假如需要制造一辆汽车,这个过程包括冲压、焊装、涂装、总装。无论制造什么汽车,都需要经历这四个工艺,如果不适用建造者模式,代码如下:

  • 汽车制造工艺抽象类
/**
 * 汽车制造工艺抽象类
 *
 * @author zhangxs
 **/
public abstract class AbstractCar {
    /** 冲压 */
    public abstract void stamping();

    /** 焊装 */
    public abstract void welding();

    /** 涂装 */
    public abstract void painting();

    /** 总装 */
    public abstract void finalAssembly();

    /** 交付 */
    public void deliver() {
        stamping();
        welding();
        painting();
        finalAssembly();
    }
}
  • 我的宾利
/**
 * 宾利
 *
 * @author zhangxs
 **/
public class Bentley extends AbstractCar{

    @Override
    public void stamping() {
        System.out.println("宾利冲压完成...");
    }

    @Override
    public void welding() {
        System.out.println("宾利焊装完成...");
    }

    @Override
    public void painting() {
        System.out.println("宾利涂装完成...");
    }

    @Override
    public void finalAssembly() {
        System.out.println("宾利总装完成...");
    }
}
  • 试了一下,很显然开起来并不爽
/**
 * 测试
 * 不用建造者模式的实现方式
 * @author zhangxs
 **/
public class Test {
    public static void main(String[] args) {
        Bentley bentley = new Bentley();
        bentley.deliver();
    }
}
  • 优点:简单易于操作,非常好理解
  • 缺点:程序结构过于简单,没有缓存层对象,扩展和维护不够友好,通俗的说,这样的方案,就好比把产品本身和产品的制造过程封装在了一起,杂乱无章,耦合性较高。

四、案例——用建造者模式创建复杂对象屏蔽创建过程

需求:还是制造汽车,嗯,这次造凯迪拉克和福特

  • 发动机接口
/**
 * 发动机接口
 * 方便演示,定义函数式接口(有且仅有一个抽象方法 可以标注上@FunctionalInterface注解),便于调用,真正业务需求自行设计决定
 * @author zhangxs
 **/
public interface Engine {
    void descEngine();
}
  • 变速箱接口
/**
 * 变速箱接口
 * 方便演示,定义函数式接口(有且仅有一个抽象方法 可以标注上@FunctionalInterface注解),便于调用,真正业务需求自行设计决定
 * @author zhangxs
 **/
public interface Transmission {
    void descTransmission();
}
  • 底盘接口
/**
 * 底盘接口
 * 方便演示,定义函数式接口(有且仅有一个抽象方法 可以标注上@FunctionalInterface注解),便于调用,真正业务需求自行设计决定
 * @author zhangxs
 **/
public interface Underpan {
    void descUnderpan();
}
  • 产品角色,以三大件举例
/**
 * 可定制三大件的汽车
 * 产品角色:一个具体的产品
 * @author zhangxs
 **/
public class Car {
    /** 发动机 */
    private Engine engine;

    /** 变速箱 */
    private Transmission transmission;

    /** 底盘 */
    private Underpan underpan;

    public Engine getEngine() {
        return engine;
    }

    public void setEngine(Engine engine) {
        this.engine = engine;
    }

    public Transmission getTransmission() {
        return transmission;
    }

    public void setTransmission(Transmission transmission) {
        this.transmission = transmission;
    }

    public Underpan getUnderpan() {
        return underpan;
    }

    public void setUnderpan(Underpan underpan) {
        this.underpan = underpan;
    }
}
  • 抽象建造者
/**
 * 抽象构建器
 * 抽象建造者:创建一个产品类对象的各个部件指定的接口或抽象类
 * @author zhangxs
 **/
public abstract class CarBuilder {
    protected Car car = new Car();

    abstract void buildEngine();

    abstract void buildTransmission();

    abstract void buildUnderpan();

    /**
     * 返回产品
     */
    public Car buildCar() {
        return car;
    }
}
  • 具体建造者:凯迪拉克
/**
 * 凯迪拉克定制构建类
 * 具体的建造者:实现接口,构建和装配各个部件
 * @author zhangxs
 **/
public class CadillacBuilder extends CarBuilder {

    @Override
    void buildEngine() {
        car.setEngine(() -> System.out.println("通用V8直喷发动机"));
    }

    @Override
    void buildTransmission() {
        car.setTransmission(() -> System.out.println("通用9AT变速箱"));
    }

    @Override
    void buildUnderpan() {
        car.setUnderpan(() -> System.out.println("基于通用EpsilonII平台,前麦弗逊独立悬架,后多连杆独立悬架"));
    }
}
  • 具体建造者:福特
/**
 * 福特定制构建类
 * 具体的建造者:实现接口,构建和装配各个部件
 * @author zhangxs
 **/
public class FordBuilder extends CarBuilder {

    @Override
    void buildEngine() {
        car.setEngine(() -> System.out.println("EcoBoost发动机"));
    }

    @Override
    void buildTransmission() {
        car.setTransmission(() -> System.out.println("福特10AT变速箱"));
    }

    @Override
    void buildUnderpan() {
        car.setUnderpan(() -> System.out.println("前麦弗逊独立悬架,后多连杆独立悬架"));
    }
}
  • 指挥者:某种程度上可以理解为4儿子店
/**
 * 指挥者类:以汽车制造这个需求来说,指挥者就是为了隔离客户与制造厂家的一个中间对象,某程度上可以理解为4S店,当然也许有更合适的,但意思就这么个意思
 * 指挥者:构建一个使用建造者接口的对象,主要用于创建一个复杂的对象,在这个过程中,发挥的作用有两个:
 *      1、隔离了客户与对象的生产过程
 *      2、负责控制产品对象的生产过程
 * @author zhangxs
 **/
public class Director {
    CarBuilder carBuilder = null;

    /**
     * 可以通过构造器传入CarBuilder
     */
    public Director(CarBuilder carBuilder) {
        this.carBuilder = carBuilder;
    }

    /**
     * 可以通过Setter方式设置CarBuilder
     */
    public void setCarBuilder(CarBuilder carBuilder) {
        this.carBuilder = carBuilder;
    }

    /**
     * 如何组装,交给指挥者
     */
    public Car construct() {
        carBuilder.buildEngine();
        carBuilder.buildTransmission();
        carBuilder.buildUnderpan();
        return carBuilder.buildCar();
    }
}
  • 话不多说,弄
/**
 * 测试
 *
 * @author zhangxs
 **/
public class Test {
    public static void main(String[] args) {
        System.out.println("=====================凯迪拉克=====================");
        showMyCar(new CadillacBuilder());
        System.out.println("=======================福特======================");
        showMyCar(new FordBuilder());
    }

    private static void showMyCar(CarBuilder carBuilder) {
        Director director = new Director(carBuilder);
        Car car = director.construct();
        car.getEngine().descEngine();
        car.getTransmission().descTransmission();
        car.getUnderpan().descUnderpan();
    }
}

五、案例——用建造者模式优化类构造器需传入较多参数的菜鸡代码

需求:嗯,又是汽车,这次用我朋友的奥迪RS7

1、不用建造者模式优化,除了显得不够大气,也没啥
  • 汽车类
/**
 * 汽车
 *
 * @author zhangxs
 **/
public class Car {
    /** 品牌 */
    private String brand;

    /** 级别 */
    private String level;

    /** 指导价 */
    private Double price;

    /** 厂商 */
    private String vendor;

    /** 能源类型 */
    private String energyType;

    public Car(String brand) {
        this.brand = brand;
    }

    public Car(String brand, Double price) {
        this.brand = brand;
        this.price = price;
    }

    public Car(String brand, String level, Double price, String vendor, String energyType) {
        this.brand = brand;
        this.level = level;
        this.price = price;
        this.vendor = vendor;
        this.energyType = energyType;
    }

    // ...可能还有更多的构造参数组合方式

    public String getBrand() {
        return brand;
    }

    public void setBrand(String brand) {
        this.brand = brand;
    }

    public String getLevel() {
        return level;
    }

    public void setLevel(String level) {
        this.level = level;
    }

    public Double getPrice() {
        return price;
    }

    public void setPrice(Double price) {
        this.price = price;
    }

    public String getVendor() {
        return vendor;
    }

    public void setVendor(String vendor) {
        this.vendor = vendor;
    }

    public String getEnergyType() {
        return energyType;
    }

    public void setEnergyType(String energyType) {
        this.energyType = energyType;
    }
}
  • 测试
/**
 * 对象构建测试
 *
 * @author zhangxs
 **/
public class Test {
    public static void main(String[] args) {
        // 构造器
        Car audi = new Car("奥迪");

        // Getter/Setter
        audi.setEnergyType("48V轻混系统");
        audi.setLevel("中大型车");
        audi.setPrice(144.88);
        audi.setVendor("Audi Sport");
        System.out.printf("%sRs7:官方指导价%f万元,出自%s厂家,能源类型为%s,属于%s\n"
                ,audi.getBrand(),audi.getPrice(),audi.getVendor(),audi.getEnergyType(),audi.getLevel());
    }
}
2、用了建造者模式优化之后,要多丝滑有多丝滑
  • 发动机类
/**
 * 发动机
 *
 * @author zhangxs
 **/
public class Engine {
    /** 型号 */
    final String model;

    /** 扭矩 */
    final String torque;

    /** 进气形式 */
    final String airIntakeForm;

    /** 气缸数 */
    final Integer cylinders;

    /** 排量 */
    final String displacement;

    private Engine(Builder builder) {
        this.model = builder.model;
        this.torque = builder.torque;
        this.airIntakeForm = builder.airIntakeForm;
        this.cylinders = builder.cylinders;
        this.displacement = builder.displacement;
    }

    public String getModel() {
        return model;
    }

    public String getTorque() {
        return torque;
    }

    public String getAirIntakeForm() {
        return airIntakeForm;
    }

    public Integer getCylinders() {
        return cylinders;
    }

    public String getDisplacement() {
        return displacement;
    }

    @Override
    public String toString() {
        return "Engine{" +
                "model='" + model + '\'' +
                ", torque='" + torque + '\'' +
                ", airIntakeForm='" + airIntakeForm + '\'' +
                ", cylinders=" + cylinders +
                ", displacement='" + displacement + '\'' +
                '}';
    }

    public static final class Builder {
        private String model;
        private String torque;
        private String airIntakeForm;
        private Integer cylinders;
        private String displacement;

        public Builder() {
        }

        public Builder setModel(String model) {
            this.model = model;
            return this;
        }

        public Builder setTorque(String torque) {
            this.torque = torque;
            return this;
        }

        public Builder setAirIntakeForm(String airIntakeForm) {
            this.airIntakeForm = airIntakeForm;
            return this;
        }

        public Builder setCylinders(Integer cylinders) {
            this.cylinders = cylinders;
            return this;
        }

        public Builder setDisplacement(String displacement) {
            this.displacement = displacement;
            return this;
        }

        /**
         * 创建实体对象,掺入this,该this就是Builder对象
         * @return builder.pattern.one.Engine
         * @author zhangxs
         * @date 2021-07-09 15:01
         */
        public Engine build() {
            return new Engine(this);
        }
    }
}
  • 测试
/**
 * 对象构建测试
 *
 * @author zhangxs
 **/
public class Test {
    public static void main(String[] args) {
        // 构建者
        Engine engine = new Engine
                .Builder()
                .setModel("DJP")
                .setTorque("800N·m")
                .setAirIntakeForm("双涡轮增压")
                .setCylinders(8)
                .setDisplacement("4.0T")
                .build();
        System.out.printf("奥迪Rs7:搭载发动机型号为%s,最大扭矩%s,进气形式为%s,包含%d个气缸,排量为%s\n"
                ,engine.getModel(),engine.getTorque(),engine.getAirIntakeForm(),engine.getCylinders(),engine.getDisplacement());
    }
}

六、总结

  • 适用场景
    1、隔离复杂对象的创建和使用,相同的方法,不同执行顺序,产生不同事件结果
    2、多个部件都可以装配到一个对象中,但产生的运行结果不相同
    3、产品类非常复杂或者产品类因为调用顺序不同而产生不同作用
    4、初始化一个对象时,参数过多,或者很多参数具有默认值
    5、不适合创建差异性很大的产品类
    6、产品内部变化复杂,会导致需要定义很多具体建造者类实现变化,增加项目中类的数量,增加系统的理解难度和运行成本
    7、需要生成的产品对象有复杂的内部结构,这些产品对象具备共性;
  • 注意事项和细节
    1、客户端即使用程序,不必知道产品内部的组成细节,将产品本身与产品的创建过程解耦,是的相同的创建过程可以创建不同的产品对象
    2、每一个具体建造者都相对独立,而与其他的具体建造者无关,因此可以很方便的替换具体建造者或增加新的具体建造者,用户使用不同的具体建造者即可得到不同的产品对象
    3、可以更加精细的控制产品的创建过程,将复杂的产品的创建步骤分解在不同的方法中,使得创建过程更加清晰,也更方便使用程序来控制创建过程
    4、增加新的具体建造者无需修改原有的相关代码,指挥者类针对抽象建造者类编程,系统扩展方便,符合开闭原则
    5、建造者模式所创建的产品一般具有较多的共同点,其组成部分相似,如果产品之间的差异性很大,则不适合使用建造者模式,因此使用的时候需要关注其适用范围
    6、如果产品的内部变化复杂,可能会导致需要定义很多具体建造者类来实现这种变化,导致系统变得庞大,因此在这种情况下,要慎重考虑,是否继续选择建造者模式
  • 抽象工厂模式 vs 建造者模式
    1、抽象工厂模式实现对产品家族的创建,一个产品家族是有这样特点的一系列产品:具有不同分类维度的产品组合,采用抽象工厂模式不需要关系构建过程,只关系什么产品由什么工厂生产即可
    2、建造者模式则是需要按照指定的蓝图建造产品,它的主要目的是通过组装零配件而产生一个新的产品
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值