建造者模式


定义

所谓万丈高楼平地起,但是我们建造(Build)高楼时,需要经历很多阶段,比如打地基、搭框架、浇筑水泥、封顶等,这些都是很难一气呵成的。所以一般我们是先建造组成高楼的各个部分,然后将其一个个地组装起来,好比搭积木一般,分阶段拼接后组装成一个完整的物体。还有个问题,就是同样的积木,同样的搭建过程,却能 Build 出不同的物体,这就叫做建造者模式。

将一个复杂的对象的构建与它的表示相分离,使得同样的构建过程可以创建出不同的表示。建造者模式(Builder Pattern)也叫做生成器模式。

组成角色

建造者模式通常有以下几部分角色组成:

  • 建造者(Builder):Builder 角色负责定义用来生成实例的接口(API);
  • 具体的建造者(ConcreateBuilder):ConcreateBuilder 角色是负责实现 Builder 角色定义的接口的实现类。针对不同的商业逻辑,具体化复杂对象的各部分的创建。在建造完成之后提供产品的实例;
  • 监工(Director):Director 角色负责使用 Builder 角色的接口 API 来生成实例。内部不涉及具体产品信息,只负责保证对象各部分完整创建或按照某种顺序进行创建。即 Director 是负责指挥如何 build 的,只负责调度,具体实施交给具体的建造者;
  • 产品(Product):即要创建的复杂对象;
  • 使用者(Client):实际使用 Builder 模式的角色,即下面的测试类。

建造者模式 UML 类图

我们还是以最开始讲的建造大楼为例,其 UML 类图大致如下:

建造者模式的代码实现如下,首先是产品类(Product):

public class Product {
    private String ground;
    private String cement;
    private String roof;

    public Product() {
    }

    public String getGround() {
        return ground;
    }

    public void setGround(String ground) {
        this.ground = ground;
    }

    public String getCement() {
        return cement;
    }

    public void setCement(String cement) {
        this.cement = cement;
    }

    public String getRoof() {
        return roof;
    }

    public void setRoof(String roof) {
        this.roof = roof;
    }
}

建造者的实现类:

public class ConcreteBuilder implements Builder{

    private final Product product = new Product();

    @Override
    public void buildGround() {
        System.out.println("build地基");
        product.setGround("build地基");
    }

    @Override
    public void buildCement() {
        System.out.println("build水泥");
        product.setGround("build水泥");
    }

    @Override
    public void buildRoof() {
        System.out.println("build楼顶");
        product.setGround("build楼顶");
    }

    @Override
    public Product buildProduct() {
        System.out.println("建造完毕!");
        return product;
    }
}

然后是我们的监工,负责指挥 builder 如何建造即如何调度:

public class Director {
    private Builder builder;

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

    public Product construct() {
        // 构建顺序:建造水泥->地基->楼顶
        builder.buildCement();
        builder.buildGround();
        builder.buildRoof();

        return builder.buildProduct();
    }
}

最后,是 Client 角色,即具体的使用者,这里的话就是测试的 Main 类:

public class Main {

    public static void main(String[] args) {
        Builder builder = new ConcreteBuilder();
        Director director = new Director(builder);
        director.construct();

    }
}

输出结果如下:

build水泥
build地基
build楼顶
建造完毕!

优缺点

  • 封装性:客户端不必知道产品内部组合细节,只需关心我们要生成某个对象,具体对象产生细节不必知晓。Main 类并不知道 Builder 类,它只是调用了 Director 类的 construct 方法完成对象的获取;
  • 建造者独立,易于拓展:上面我们只列举了 ConcreteBuilder 建造者类,如果需要其它建造者新建类即可。建造者之间彼此独立,系统拓展性好,符合开闭原则;
  • 便于控制细节风险:由于具体建造者是独立的,因此可以对具体建造过程逐步细化,不会对其它模块产生影响。

    应用场景

  • 产品类非常复杂,不同的调度产生不同的结果时,使用建造者模式比较适合;
  • 相同的组件或配件都可以装配到一个对象,但是产生的结果又不相同,可以使用建造者模式。

建造者模式 VS 工厂方法模式

建造者模式关注的是零件类型和装配顺序(工艺)同为创建型模式,注重点不同。另外工厂模式只有一个建造方法,而建造者模式有多个建造零部件的方法并且强调建造顺序,而工厂模式没有顺序的概念。

总结

将复杂物体的构建与表现相分离,这就是建造者模式,很像生活中搭积木这种,一个个按需要按方式进行拼凑,建造者模式适应于产品类比较复杂调度方式不一的场景。


Author: Re:0
Reprint policy: All articles in this blog are used except for special statements CC BY 4.0 reprint policy. If reproduced, please indicate source Re:0 !
 Previous
原型模式 原型模式
设计一个类的时候,我们通常会使用到构造函数,这里类和对象的关系好比模具和构件的关系,对象总是从类中创建的。但是某些场景下是不允许类的调用者直接调用构造函数,也就说对象未必需要从类中衍生出来,现实生活中存在太多案例是通过直接 “克隆” 来产生
2022-03-07
Next 
RabbitMQ延迟队列 RabbitMQ延迟队列
什么是延迟队列延迟队列就是进入该队列的消息会被延迟消费的队列。而一般的队列,消息一旦入队了之后就会被消费者马上消费。
2022-03-07
  TOC