建造者模式

160 阅读4分钟

1. 概述

建造者模式(生成器模式 Builder Pattern)是一种对象构造模式,他可以将复杂对象的建造过程抽象出来,使这个抽象过程的不同实现方法可以构造出不同表现的对象

建造者模式 是一步一步创建一个复杂的对象,它允许用户只通过指定复杂对象 的类型和内容就可以构建它们,用户不需要知道内部的具体构建细节

2. UML类图

  • Product 就是所需要创建的产品
  • Builder 创建一个Poroduct对象的各个部分的指定的 接口/抽象类
  • ConcreteBuilder 具体的一个创建者,实现Builder中的各个方法,完成各个部分建造的具体实现
  • Director 建造的指挥者,内含有一个Builder接口,既然是指挥者,作用就是指挥Builder接口按照自己设定的流程安排每一个部分应该怎么执行,然后得到Builder创建的对象并交给客户端。所以指挥者还有一个作用是隔离客户和产品的生产过程

3. 实例

使用建造者模式呈现一个房子(包含地基、墙体、天花板)的建造过程

我们分UML类图中的四个部分来查看

3.1 Product -- House类

public class House {
    private String basic;
    private String wall;
    private String roof;
    
    constructor...getter...setter...toString...
}

House类或者说产品类,只需要含有产品所需的属性即可

3.2 Builder -- HouseBuilder类

这是一个抽象类,含有一个产品的对象,和建造产品各个属性的对应的方法,这里有三个方法来分别建造房子的三个部分,然后buildHouse方法是将建造好的房子返回

public abstract class HouseBuilder {
    protected House house = new House();

    // 将建造的流程写好,使用的都是抽象方法
    public abstract void buildBasic();
    public abstract void buildWalls();
    public abstract void roofed();

    // 建造房子
    public House buildHouse() {
        return house;
    }
}

建造各个部分的方法都是抽象方法,交给子类去实现;而buildHouse()的方法直接将产品对象返回

3.3 ConcreteBuilder -- CommonHouseBuilder类

该类是Builder抽象类/接口的具体实现类,实现了创建各个部分的方法具体的实现过程

public class CommonHouseBuilder extends HouseBuilder {
    @Override
    public void buildBasic() {
        super.house.setBasic("普通房子打地基10米");
    }

    @Override
    public void buildWalls() {
        super.house.setWall("普通房子砌粉墙");
    }

    @Override
    public void roofed() {
        super.house.setRoof("普通房子的天花板是砖块");
    }
}

注意这里构造的对象的父类也就是抽象Builder类中的那个产品对象,所以都使用的是super.house

3.4 Director -- HouseDirector类

指挥类含有一个Builder接口,指挥其按照设定的步骤创建各个部分

public class HouseDirector {
    // 使用的是抽象类,运用多态
    private HouseBuilder houseBuilder;

    public HouseDirector() {
    }

    public HouseDirector(HouseBuilder houseBuilder) {
        this.houseBuilder = houseBuilder;
    }

    public HouseBuilder getHouseBuilder() {
        return houseBuilder;
    }

    public void setHouseBuilder(HouseBuilder houseBuilder) {
        this.houseBuilder = houseBuilder;
    }

    // 如何处理建造房子的流程,交给指挥者
    // 也就是指挥者只会builder将各个部分按照自定义的流程创建然后返回创建好的产品
    public House buildHouse() {
        // 使用建造者的创建流程
        houseBuilder.buildBasic();
        houseBuilder.buildWalls();
        houseBuilder.roofed();

        // 然后返回建造者创建好的对象
        return houseBuilder.buildHouse();
    }
}

需要设置具体的HouseBuilder的类型,才能够知道要指挥的是建造什么房子的创建者

3.5 使用

public class Client {
    public static void main(String[] args) {
        // 使用普通房的HouseBuilder来建造房子
        System.out.println(new HouseDirector(new CommonHouseBuilder()).buildHouse());
    }
}

如果需要增加一种房子,比如增加别墅,由于房子都离不开那三种元素,所以我们只需要增加一个别墅的Builder,继承HouseBuilder,然后实现其中建造各个部分的代码即可。需要建造别墅,就将别墅的Builder对象传入Director,就能够建造别墅了!

4. 总结

  1. 客户端(使用程序)不必知道产品内部组成的细节,将产品本身与产品的创建过程解耦,使得相同的创建过程可以创建不同的产品对象
  2. 每一个具体建造者都相对独立,而与其他的具体建造者无关,因此可以很方便地替换具体建造者或增加新的具体建造者,用户使用不同的具体建造者即可得到不同的产品对象
  3. 可以更加精细地控制产品的创建过程 。将复杂产品的创建步骤分解在不同的方法中,使得创建过程更加清晰,也更方便使用程序来控制创建过程
  4. 增加新的具体建造者无须修改原有类库的代码,指挥者类针对抽象建造者类编程,系统扩展方便,符合 “开闭原则”