带你了解不一样的建造者模式

1,058 阅读5分钟

这是我参与2022首次更文挑战的第6天,活动详情查看:2022首次更文挑战

带你了解不一样的建造者模式

概念

建造者模式(Builder Pattren)是指将一个复杂对象的构造与它的表示分离,使同样的构建过程可以创建不同的表示,根据类的过程,建造者模式属于创建型模式。

建造者模式是将一个复杂的对象分解为多个简单并不可划分的对象,然后一步一步构建而成。它将变与不变相分离,即产品的组成部分是不变的,但每一部分是可以灵活选择的。使用建造者模式对于用户来讲只需要指定需要建造的类型就可以获得对象,关于对象的创建和细节都不需要有过多的了解。

应用场景

建造者模式主要适用于复杂产品的创建,当需要创建的产品具备复杂创建过程时,可以抽取出共性创建过程,然后交由具体实现类自定义创建流程,使得同样的创建行为可以生产出不同的产品,分离了创建与表示,使创建产品的灵活性大大增加。

建造者模式主要适用于以下应用场景:

  • 相同的方法,不同的执行顺序,产生不同的结果。

  • 多个部件或零件,都可以装配到一个对象中,但是产生的结果又不相同。

  • 产品类非常复杂,或者产品类中不同的调用顺序产生不同的作用。

  • 初始化一个对象特别复杂,参数多,而且很多参数都具有默认值。

基本用法

通过代码来展示建造者模式的不同用法

  • Computer
public class Computer {

    //显示器
    private String displayed;
    //主机
    private String mainUnit;
    //鼠标
    private String mouse;
    //键盘
    private String keyboard;

    @Override
    public String toString() {
        return "Computer{" +
                "displayed='" + displayed + ''' +
                ", mainUnit='" + mainUnit + ''' +
                ", mouse='" + mouse + ''' +
                ", keyboard='" + keyboard + ''' +
                '}';
    }
}

创建电脑产品类,Computer声明需要创建的变量

  • ComputerBuilder
public class ComputerBuilder {

    private Computer computer = new Computer();


    public void installDisplayed(String displayer) {
        computer.setDisplayed(displayer);
    }

    public void installMainUnit(String mainUnit) {
        computer.setMainUnit(mainUnit);
    }

    public void installMouse(String mouse) {
        computer.setMouse(mouse);
    }

    public void installKeyboard(String keyboard) {
        computer.setKeyboard(keyboard);
    }

    public Computer getComputer() {
        return computer;
    }
}

创建ComputerBuilder类,建造者类将复杂的构建过程都封装起来,构建Computer的步骤由用户来决定。

  • MainTest
public class MainTest {
    public static void main(String[] args) {
        ComputerBuilder computerBuilder = new ComputerBuilder();
        computerBuilder.installMainUnit("主机");
        computerBuilder.installMouse("鼠标");
        computerBuilder.installDisplayed("显示器");
        computerBuilder.installKeyboard("键盘");
        Computer computer = computerBuilder.getComputer();
        System.out.println(computer);
    }
}
  • 结果

image.png

测试类声明建造方法,设置对应的属性,通过结果可以看到对应的请求。不需要关心如何创建。

  • 基本流程图

image.png

链式写法

链式写法和普通写法又着明显的区别,但是效率上基本上都相差无几,从代码中展示

  • abstract
public abstract class AbstractBuilder {
    public Phone phone;

    abstract AbstractBuilder customCPU(String cpu);

    abstract AbstractBuilder customMem(String mem);

    abstract AbstractBuilder customDisk(String disk);

    abstract AbstractBuilder customCamera(String camera);

    public Phone getProduct() {
        return phone;
    }
}
  • XiaoMiBuilder
public class XiaoMiBuilder extends AbstractBuilder {

    public XiaoMiBuilder() {
        phone = new Phone();
    }
    @Override
    AbstractBuilder customCPU(String cpu) {
        phone.setCpu(cpu);
        return this;
    }
    @Override
    AbstractBuilder customMem(String mem) {
        phone.setMem(mem);
        return this;
    }
    @Override
    AbstractBuilder customDisk(String disk) {
        phone.setDisk(disk);
        return this;
    }
    @Override
    AbstractBuilder customCamera(String camera) {
        phone.setCamera(camera);
        return this;
    }
}
  • MainTest
public class MainTest {
    public static void main(String[] args) {
        AbstractBuilder xiaoMiBuilder = new XiaoMiBuilder();
        Phone product = xiaoMiBuilder.customCPU("晓龙888")
                .customMem("16G")
                .customDisk("512G")
                .customCamera("索尼").getProduct();
        System.out.println(product);

    }
}
  • 流程图

image.png

建造者角色

  • 产品角色(Product):它是包含多个组成部件的复杂对象,由具体建造者来创建其各个零部件。

  • 抽象建造者(Builder):它是一个包含创建产品各个子部件的抽象方法的接口,通常还包含一个返回复杂产品的方法 getResult()。

  • 具体建造者(Concrete Builder):实现 Builder 接口,完成复杂产品的各个部件的具体创建方法。

  • 指挥者(Director):它调用建造者对象中的部件构造与装配方法完成复杂对象的创建,在指挥者中不涉及具体产品的信息。

建造者模式在源码中的体现

  • JDK源码中StringBuilder方法

image.png

  • Mybatis源码只能够Cache源码方法
Cache cache = new CacheBuilder(currentNamespace)
        //这里如果我们定义了<cache/>中的type,就使用自定义的Cache,否则使用和一级缓存相同的PerpetualCache
        .implementation(valueOrDefault(typeClass, PerpetualCache.class))
        .addDecorator(valueOrDefault(evictionClass, LruCache.class))
        .clearInterval(flushInterval)
        .size(size)
        .readWrite(readWrite)
        .blocking(blocking)
        .properties(props)
        .build();
  • String源码中的BeanDefintionBuilder方法

image.png

建造者模式的优缺点

优点

  • 类与类之间的封装性很好, 类的创建和对外的展示分类,符合设计模式七大原则的接口隔离原则

  • 扩展性能比较好,每一个具体的建造者方法都相互独立,有利于系统的接偶操作

  • 对于权限安全这一块有着很好的控制,使用者知不知道建造者类具体的实现细节,只需要知道如何使用,不会对其他的模块产生任何影响。

缺点

  1. 产品的组成部分必须相同,这限制了其使用范围。
  2. 如果产品的内部变化复杂,如果产品内部发生变化,则建造者也要同步修改,后期维护成本较大。

建造者模式与工厂模式的区别

建造者模式和工厂模式的关注点不同:建造者模式注重零部件的组装过程,而工厂方法模式更注重零部件的创建过程,但两者可以结合使用。

  • 建造者模式更加注重方法的调用顺序,工厂模式注重创建对象。

  • 创建对象的力度不同,建造者模式创建复杂的对象,由各种复杂的部件组成,工厂模式创建出来的对象都一样

  • 关注重点不一样,工厂模式只需要把对象创建出来就可以了,而建造者模式不仅要创建出对象,还要知道对象由哪些部件组成。

  • 建造者模式根据建造过程中的顺序不一样,最终对象部件组成也不一样。