设计模式 04 建造者模式

建造者模式(Builder Pattern)属于创建型模式

概述

建造者模式使用多个简单的对象一步一步构建成一个复杂的对象。

一个 Builder 类会一步一步构造最终的对象。该 Builder 类是独立于其他对象的。

经常使用的 StringBuiler 就是建造者模式的典型实现。

代码实现

普通实现

先来看下建造者模式的普通实现。这里模拟快餐店点餐场景:

1、定义快餐食品

/**
 * 快餐食品(产品)
 */
public class Product {

    /**
     * 快餐 A 默认为汉堡
     */
    private String BuildA = "汉堡";

    /**
     * 快餐 B 默认为可乐
     */
    private String BuildB = "可乐";

    /**
     * 快餐 C 默认为薯条
     */
    private String BuildC = "薯条";

    /**
     * 快餐 D 默认为甜点
     */
    private String BuildD = "甜点";

    public String getBuildA() {
        return BuildA;
    }

    public void setBuildA(String buildA) {
        BuildA = buildA;
    }

    public String getBuildB() {
        return BuildB;
    }

    public void setBuildB(String buildB) {
        BuildB = buildB;
    }

    public String getBuildC() {
        return BuildC;
    }

    public void setBuildC(String buildC) {
        BuildC = buildC;
    }

    public String getBuildD() {
        return BuildD;
    }

    public void setBuildD(String buildD) {
        BuildD = buildD;
    }

    @Override
    public String toString() {
        return "Product{" +
                "BuildA='" + BuildA + '\'' +
                ", BuildB='" + BuildB + '\'' +
                ", BuildC='" + BuildC + '\'' +
                ", BuildD='" + BuildD + '\'' +
                '}';
    }
}

2、定义厨房

/**
 * 厨房(建造者)
 */
public abstract class Kitchen {

    /**
     * 制作快餐 A
     * @param msg 快餐名称
     * @return 快餐
     */
    abstract Kitchen builderA(String msg);

    /**
     * 制作快餐 B
     * @param msg 快餐名称
     * @return 快餐
     */
    abstract Kitchen builderB(String msg);

    /**
     * 制作快餐 C
     * @param msg 快餐名称
     * @return 快餐
     */
    abstract Kitchen builderC(String msg);

    /**
     * 制作快餐 D
     * @param msg 快餐名称
     * @return 快餐
     */
    abstract Kitchen builderD(String msg);

    /**
     * 获取产品
     * @return 产品
     */
    abstract Product getProduct();
}

3、定义服务员

/**
 * 服务员(传递者)
 */
public class Waiter extends Kitchen {

    private Product product;

    public Waiter(){
        product = new Product();
    }
    
    @Override
    Kitchen builderA(String msg) {
        product.setBuildA(msg);
        return this;
    }

    @Override
    Kitchen builderB(String msg) {
        product.setBuildB(msg);
        return this;
    }

    @Override
    Kitchen builderC(String msg) {
        product.setBuildC(msg);
        return this;
    }

    @Override
    Kitchen builderD(String msg) {
        product.setBuildD(msg);
        return this;
    }

    @Override
    Product getProduct() {
        return product;
    }

}

4、客人点餐

// 叫服务员
Waiter waiter = new Waiter();

// 可以选择套餐,省事,直接告诉服务员要套餐即可
Product product1 = waiter.getProduct();

System.out.println(product1);

// 也可以自己点餐,点了哪些上哪些
Product product2 = waiter
    .builderA("炸鸡")
    .builderB("雪碧")
    .builderC(null)
    .builderD(null)
    .getProduct();

System.out.println(product2);

输出结果为:

Product{BuildA='汉堡', BuildB='可乐', BuildC='薯条', BuildD='甜点'}
Product{BuildA='炸鸡', BuildB='雪碧', BuildC='null', BuildD='null'}

如果选择套餐,就按照套餐默认的快餐食品送餐。

如果自己点餐,就按照点的送餐,点了哪些上哪些。

指挥者实现

在工地建筑时,除了建造本身,建造的顺序也非常重要,因此工地上一般都会有一个指挥者来决定建造的顺序。

1、定义一栋楼(产品)

/**
 * 一栋楼(产品)
 */
public class Product {

    /**
     * 地基
     */
    private String productA;

    /**
     * 主体
     */
    private String productB;

    /**
     * 粉刷
     */
    private String productC;

    /**
     * 绿化
     */
    private String productD;

    public String getProductA() {
        return productA;
    }

    public void setProductA(String productA) {
        this.productA = productA;
    }

    public String getProductB() {
        return productB;
    }

    public void setProductB(String productB) {
        this.productB = productB;
    }

    public String getProductC() {
        return productC;
    }

    public void setProductC(String productC) {
        this.productC = productC;
    }

    public String getProductD() {
        return productD;
    }

    public void setProductD(String productD) {
        this.productD = productD;
    }

    @Override
    public String toString() {
        return "Product{" +
                "productA='" + productA + '\'' +
                ", productB='" + productB + '\'' +
                ", productC='" + productC + '\'' +
                ", productD='" + productD + '\'' +
                '}';
    }
}

2、定义包工头(抽象建造者)

/**
 * 包工头(抽象建造者)
 * @author yifan
 */
public abstract class Builder {

    /**
     * 打地基
     */
    abstract void buildA();

    /**
     * 建主体
     */
    abstract void buildB();

    /**
     * 去粉刷
     */
    abstract void buildC();

    /**
     * 搞绿化
     */
    abstract void buildD();

    /**
     * 建一栋楼
     * @return 一栋楼
     */
    abstract Product getProduct();
}

3、定义工人(实际建造者)

/**
 * 工人(实际建造者)
 */
public class Worker extends Builder{

    private Product product;

    public Worker() {
        // 指定要建设的楼
        product = new Product();
    }

    @Override
    void buildA() {
        product.setProductA("地基");
        System.out.println("地基");
    }

    @Override
    void buildB() {
        product.setProductB("主体");
        System.out.println("主体");
    }

    @Override
    void buildC() {
        product.setProductC("粉刷");
        System.out.println("粉刷");
    }

    @Override
    void buildD() {
        product.setProductD("绿化");
        System.out.println("绿化");
    }

    @Override
    Product getProduct() {
        return product;
    }
}

4、定义施工调度员(指挥者)

/**
 * 施工调度员(指挥者)
 */
public class Director {

    /**
     * 指挥包工头按照顺序建楼
     * @param builder 包工头
     * @return 楼
     */
    public Product build(Builder builder){
        
        builder.buildA();
        builder.buildB();
        builder.buildC();
        builder.buildD();
        return builder.getProduct();
        
    }
}

5、测试

// 施工调度员指挥包工头,包工头找到具体的工人按照施工调度员指定的顺序建造
new Director().build(new Worker());

这样就用代码实现了工地上各岗位的协作,如果工程需要调整建造顺序,只需要更改指挥者的 build 方法即可,非常方便。

设计模式的思想起源于建筑行业,从建造者模式这里就能体现得淋漓尽致。

优缺点

优点

1、建造者独立,易扩展。

2、便于控制细节风险。

缺点

1、产品必须有共同点,范围有限制。

2、如内部变化复杂,会有很多的建造类。

使用场景

1、需要生成的对象具有复杂的内部结构。

2、需要生成的对象内部属性本身相互依赖。

注意事项

工厂模式的区别是:建造者模式更加关注与零件装配的顺序。


参考

https://www.bilibili.com/video/BV1mc411h719?p=5&vd_source=299f4bc123b19e7d6f66fefd8f124a03

posted @ 2022-07-12 21:07  天航星  阅读(38)  评论(0编辑  收藏  举报