菜单

Juning
发布于 2020-03-16 / 1245 阅读
2
0

设计模式——建造者模式

在我们的开发过程中可能需要创建一个非常复杂的对象,这个复杂对象通常由多个子部件按一定的步骤组合而成
就像手机是有CPU,屏幕,内存,存储等一些部件构成,而一般的手机厂商也不可能自己去组装一台手机,一般是由手机厂商将手机的设计图纸给到手机代工工厂,代工工厂安排生产线去生产线去生产一个成品的手机,然后再将手机给到手机厂商进行销售
其实我们在生活中还有很多这样的例子,比如我们要去组装一台电脑,电脑的构成有CPU、主板、内存、硬盘、显卡等部件
而电脑的配置清单又可以根据实际情况来进行改变,就比如CPU,我们可以选择英特尔的9900K,又可以选择AMD的3990X等等...
以上所有这些产品都是由多个部件构成的,各个部件可以灵活选择,但其创建步骤都大同小异
这类产品的创建无法用前面介绍的工厂模式描述,只有建造者模式可以很好地描述这一类产品的创建

定义与特点

建造者(Builder)模式是指将一个复杂对象的构造与它的表示分离,使同样的构建过程可以创建不同的表示,它是将一个复杂的对象分解为多个简单的对象,然后一步一步构建而成。它将变与不变相分离,即产品的组成部分是不变的,但每一部分是可以灵活选择的
值得一提的是建造者模式和工厂模式的关注点不同:建造者模式注重零部件的组装过程,而工厂方法模式更注重零部件的创建过程,但两者可以结合使用
建造者的优点如下:

  • 各个具体的建造者相互独立,有利于系统的扩展
  • 客户端不必知道产品内部组成的细节,便于控制细节风险。

当然也有缺点:

  • 产品的组成部分必须相同,限制了它的使用范围
  • 如果产品的内部变化复杂,就会增加很多的建造者类

结构与实现

建造者模式的结构如下图所示:
image.png

  1. 产品角色(Product):它是包含多个组成部件的复杂对象,由具体建造者来创建其各个零部件
  2. 抽象建造者(Builder):它是一个包含创建产品各个子部件的抽象方法的接口,通常还包含一个返回复杂产品的方法
  3. 具体建造者(Concrete Builder):实现Builder接口,完成复杂产品的各个部件的具体创建方法
  4. 指挥者(Director):指挥者不涉及具体产品的信息,它调用建造者对象中的部件构造与装配方法完成复杂对象的创建

我们以最上面所说的组装电脑为例:
产品角色(Product):

/**
 * 产品角色
 * 手机信息
 */
public class MobilePhoneInfo {

    // 产品名称
    private String name;

    // 处理器
    private String cpu;

    // 屏幕大小
    private String screenSize;

    // 屏幕分辨率
    private String screenResolution;

    // 内存
    private String memory;

    // 存储
    private String storage;

    public void setName(String name) {
        this.name = name;
    }

    public void setCpu(String cpu) {
        this.cpu = cpu;
    }

    public void setScreenSize(String screenSize) {
        this.screenSize = screenSize;
    }

    public void setScreenResolution(String screenResolution) {
        this.screenResolution = screenResolution;
    }

    public void setMemory(String memory) {
        this.memory = memory;
    }

    public void setStorage(String storage) {
        this.storage = storage;
    }

    public void show() {
        System.err.println("产品名称:" + name);
        System.err.println("处理器名称:" + cpu);
        System.err.println("屏幕大小:" + screenSize);
        System.err.println("屏幕分辨率:" + screenResolution);
        System.err.println("内存:" + memory);
        System.err.println("存储控件:" + storage);
    }
}

抽象建造者(Builder):

/**
 * 抽象建造者
 * 富士康
 */
abstract class Builder {

    // 根据手机功能模板组装生产线
    protected MobilePhoneInfo mobilePhoneInfo = new MobilePhoneInfo();
    public abstract void buildName();
    public abstract void buildCpu();
    public abstract void buildScreenSize();
    public abstract void buildScreenResolution();
    public abstract void buildMemory();
    public abstract void buildStorage();

    // 返回产品对象
    public MobilePhoneInfo getMobilePhoneInfo() {
        return mobilePhoneInfo;
    }
}

具体建造者(Concrete Builder):

/**
 * 具体建造者
 * 组装工人
 */
public class ConcreteBuilder extends Builder {
    @Override
    public void buildName() {
        mobilePhoneInfo.setName("Apple 11 Pro max");
    }

    @Override
    public void buildCpu() {
        mobilePhoneInfo.setCpu("A13");
    }

    @Override
    public void buildScreenSize() {
        mobilePhoneInfo.setScreenSize("6.5英寸");
    }

    @Override
    public void buildScreenResolution() {
        mobilePhoneInfo.setScreenResolution("2688x1242像素");
    }

    @Override
    public void buildMemory() {
        mobilePhoneInfo.setMemory("4GB");
    }

    @Override
    public void buildStorage() {
        mobilePhoneInfo.setStorage("512GB");
    }
}

指挥者(Director):

/**
 * 指挥者
 * 硬件设计师
 */
public class Director {

    // 组装工厂(富士康)
    private Builder builder;

    public Director(Builder builder){
        this.builder = builder;
    }

    // 开始组装
    public MobilePhoneInfo construct() {
        builder.buildName();
        builder.buildCpu();
        builder.buildScreenSize();
        builder.buildScreenResolution();
        builder.buildMemory();
        builder.buildStorage();
        return builder.getMobilePhoneInfo();
    }
}

客户端(Client):

/**
 * 客户端
 * 苹果、华为、小米。。。
 */
public class Client {
    public static void main(String[] args) {
        // 我想制造一款手机
        Builder builder = new ConcreteBuilder();

        // 硬件工程师指挥制造
        Director director = new Director(builder);

        // 工厂交货
        MobilePhoneInfo mobilePhoneInfo = director.construct();

        // 手机的信息
        mobilePhoneInfo.show();
    }
}

运行结果如下:
image.png

应用场景

建造者模式创建的是复杂对象,其产品的各个部分经常面临着剧烈的变化,但将它们组合在一起的算法却相对稳定,所以它通常在以下场合使用:

  • 创建的对象较复杂,由多个部件构成,各部件面临着复杂的变化,但构件间的建造顺序是稳定的
  • 创建复杂对象的算法独立于该对象的组成部分以及它们的装配方式,即产品的构建过程和最终的表示是独立的

扩展

在应用过程中可以根据需要改变,如果创建的产品种类只有一种,只需要一个具体建造者,这时可以去掉抽象建造者,甚至可以去掉指挥者角色


评论