Skip to content

建造者模式

引言

在软件开发中,我们常常会遇到一些复杂的对象,它们通常由多个部分组成,并且这些部分之间有复杂的依赖关系。如果我们直接使用构造方法或者工厂模式来创建这些对象,代码将变得冗长且难以维护。为了解决这个问题,建造者模式(Builder Pattern)应运而生。建造者模式将一个复杂对象的构建与其表示分离,使得同样的构建过程可以创建不同的表示。

诞生背景

建造者模式最早由《设计模式:可复用面向对象软件的基础》一书提出,是 23 种经典设计模式之一。它主要用于解决对象创建过程复杂、构造参数多的问题。通过将构建过程与最终对象分离,建造者模式提供了一种更灵活的对象创建方式。

演进过程

  • GoF 设计模式提出:建造者模式由 Erich Gamma 等人在《设计模式》一书中正式命名并定义。
  • 与工厂模式结合使用:建造者模式常与工厂模式结合使用,工厂用于管理建造者实例的创建。
  • 链式调用支持:现代语言(如 Java 和 PHP)支持链式调用后,建造者模式实现更加简洁流畅。
  • 构建不可变对象:随着不可变对象(Immutable Object)理念的发展,建造者模式成为创建复杂不可变对象的有效手段。

核心概念

建造者模式主要涉及以下几个角色:

  • Builder(建造者接口):定义创建一个产品对象的不同步骤。
  • ConcreteBuilder(具体建造者):实现 Builder 接口中定义的方法,并返回构建好的产品。
  • Director(指挥者):负责调用建造者的方法来构建产品,它不关心具体产品是如何构建的,只负责构建过程的顺序。
  • Product(产品):被构建的复杂对象,由多个部分组成。

通用实现

Java 实现

java
// 产品类
class House {
    private String foundation;
    private String walls;
    private String roof;

    public void setFoundation(String foundation) {
        this.foundation = foundation;
    }

    public void setWalls(String walls) {
        this.walls = walls;
    }

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

    @Override
    public String toString() {
        return "House{" +
                "foundation='" + foundation + '\'' +
                ", walls='" + walls + '\'' +
                ", roof='" + roof + '\'' +
                '}';
    }
}

// 建造者接口
interface HouseBuilder {
    void buildFoundation();
    void buildWalls();
    void buildRoof();
    House getHouse();
}

// 具体建造者
class ConcreteHouseBuilder implements HouseBuilder {
    private House house;

    public ConcreteHouseBuilder() {
        this.house = new House();
    }

    @Override
    public void buildFoundation() {
        house.setFoundation("Concrete Foundation");
    }

    @Override
    public void buildWalls() {
        house.setWalls("Brick Walls");
    }

    @Override
    public void buildRoof() {
        house.setRoof("Tile Roof");
    }

    @Override
    public House getHouse() {
        return house;
    }
}

// 指挥者
class Director {
    private HouseBuilder houseBuilder;

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

    public void constructHouse() {
        houseBuilder.buildFoundation();
        houseBuilder.buildWalls();
        houseBuilder.buildRoof();
    }
}

// 客户端代码
public class Client {
    public static void main(String[] args) {
        Director director = new Director();
        HouseBuilder builder = new ConcreteHouseBuilder();
        director.setHouseBuilder(builder);
        director.constructHouse();

        House house = builder.getHouse();
        System.out.println(house);
    }
}

php 实现

php
// 产品类
class House {
    private $foundation;
    private $walls;
    private $roof;

    public function setFoundation($foundation) {
        $this->foundation = $foundation;
    }

    public function setWalls($walls) {
        $this->walls = $walls;
    }

    public function setRoof($roof) {
        $this->roof = $roof;
    }

    public function __toString() {
        return "House(foundation: {$this->foundation}, walls: {$this->walls}, roof: {$this->roof})";
    }
}

// 建造者接口
interface HouseBuilder {
    public function buildFoundation();
    public function buildWalls();
    public function buildRoof();
    public function getHouse();
}

// 具体建造者
class ConcreteHouseBuilder implements HouseBuilder {
    private $house;

    public function __construct() {
        $this->house = new House();
    }

    public function buildFoundation() {
        $this->house->setFoundation("Concrete Foundation");
    }

    public function buildWalls() {
        $this->house->setWalls("Brick Walls");
    }

    public function buildRoof() {
        $this->house->setRoof("Tile Roof");
    }

    public function getHouse() {
        return $this->house;
    }
}

// 指挥者
class Director {
    private $houseBuilder;

    public function setHouseBuilder(HouseBuilder $builder) {
        $this->houseBuilder = $builder;
    }

    public function constructHouse() {
        $this->houseBuilder->buildFoundation();
        $this->houseBuilder->buildWalls();
        $this->houseBuilder->buildRoof();
    }
}

// 客户端代码
$builder = new ConcreteHouseBuilder();
$director = new Director();
$director->setHouseBuilder($builder);
$director->constructHouse();

$house = $builder->getHouse();
echo $house . PHP_EOL;

应用场景

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

  • 当一个对象需要由多个部分组成,且构建过程较为复杂。
  • 当不同构建步骤可以产生不同的表示(如不同的产品配置)。
  • 当需要隔离复杂对象的创建和使用,使得代码更清晰。
  • 当希望构建不可变对象时。

案例

一个典型的建造者模式案例是“计算机配置构建”。计算机可以有多种配置,如内存大小、CPU 型号、硬盘容量等。通过建造者模式,我们可以构建不同配置的计算机。

java 实现

java
// 产品类
class Computer {
    private String cpu;
    private int ram;
    private int storage;

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

    public void setRam(int ram) {
        this.ram = ram;
    }

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

    @Override
    public String toString() {
        return "Computer{" +
                "cpu='" + cpu + '\'' +
                ", ram=" + ram +
                "GB, storage=" + storage +
                "GB}";
    }
}

// 建造者接口
interface ComputerBuilder {
    void buildCpu();
    void buildRam();
    void buildStorage();
    Computer getComputer();
}

// 具体建造者
class GamingComputerBuilder implements ComputerBuilder {
    private Computer computer;

    public GamingComputerBuilder() {
        computer = new Computer();
    }

    @Override
    public void buildCpu() {
        computer.setCpu("Intel i9");
    }

    @Override
    public void buildRam() {
        computer.setRam(32);
    }

    @Override
    public void buildStorage() {
        computer.setStorage(1000);
    }

    @Override
    public Computer getComputer() {
        return computer;
    }
}

// 另一个具体建造者
class OfficeComputerBuilder implements ComputerBuilder {
    private Computer computer;

    public OfficeComputerBuilder() {
        computer = new Computer();
    }

    @Override
    public void buildCpu() {
        computer.setCpu("Intel i5");
    }

    @Override
    public void buildRam() {
        computer.setRam(16);
    }

    @Override
    public void buildStorage() {
        computer.setStorage(500);
    }

    @Override
    public Computer getComputer() {
        return computer;
    }
}

// 指挥者
class Director {
    private ComputerBuilder builder;

    public void setBuilder(ComputerBuilder builder) {
        this.builder = builder;
    }

    public void constructComputer() {
        builder.buildCpu();
        builder.buildRam();
        builder.buildStorage();
    }
}

// 客户端代码
public class Client {
    public static void main(String[] args) {
        Director director = new Director();

        // 构建游戏电脑
        ComputerBuilder gamingBuilder = new GamingComputerBuilder();
        director.setBuilder(gamingBuilder);
        director.constructComputer();
        Computer gamingComputer = gamingBuilder.getComputer();
        System.out.println(gamingComputer);

        // 构建办公电脑
        ComputerBuilder officeBuilder = new OfficeComputerBuilder();
        director.setBuilder(officeBuilder);
        director.constructComputer();
        Computer officeComputer = officeBuilder.getComputer();
        System.out.println(officeComputer);
    }
}

php 实现

php
// 产品类
class Computer {
    private $cpu;
    private $ram;
    private $storage;

    public function setCpu($cpu) {
        $this->cpu = $cpu;
    }

    public function setRam($ram) {
        $this->ram = $ram;
    }

    public function setStorage($storage) {
        $this->storage = $storage;
    }

    public function __toString() {
        return "Computer(cpu: {$this->cpu}, ram: {$this->ram}GB, storage: {$this->storage}GB)";
    }
}

// 建造者接口
interface ComputerBuilder {
    public function buildCpu();
    public function buildRam();
    public function buildStorage();
    public function getComputer();
}

// 具体建造者 - 游戏电脑
class GamingComputerBuilder implements ComputerBuilder {
    private $computer;

    public function __construct() {
        $this->computer = new Computer();
    }

    public function buildCpu() {
        $this->computer->setCpu("Intel i9");
    }

    public function buildRam() {
        $this->computer->setRam(32);
    }

    public function buildStorage() {
        $this->computer->setStorage(1000);
    }

    public function getComputer() {
        return $this->computer;
    }
}

// 具体建造者 - 办公电脑
class OfficeComputerBuilder implements ComputerBuilder {
    private $computer;

    public function __construct() {
        $this->computer = new Computer();
    }

    public function buildCpu() {
        $this->computer->setCpu("Intel i5");
    }

    public function buildRam() {
        $this->computer->setRam(16);
    }

    public function buildStorage() {
        $this->computer->setStorage(500);
    }

    public function getComputer() {
        return $this->computer;
    }
}

// 指挥者
class Director {
    private $builder;

    public function setBuilder(ComputerBuilder $builder) {
        $this->builder = $builder;
    }

    public function constructComputer() {
        $this->builder->buildCpu();
        $this->builder->buildRam();
        $this->builder->buildStorage();
    }
}

// 客户端代码
$gamingBuilder = new GamingComputerBuilder();
$officeBuilder = new OfficeComputerBuilder();
$director = new Director();

// 构建游戏电脑
$director->setBuilder($gamingBuilder);
$director->constructComputer();
$gamingComputer = $gamingBuilder->getComputer();
echo $gamingComputer . PHP_EOL;

// 构建办公电脑
$director->setBuilder($officeBuilder);
$director->constructComputer();
$officeComputer = $officeBuilder->getComputer();
echo $officeComputer . PHP_EOL;

优点

  • 解耦构建逻辑与表示:建造者将构建过程与最终对象解耦,使得构建过程可以复用。
  • 易于扩展:新增一种产品只需增加一个具体建造者,符合开闭原则。
  • 控制构建过程:可以精细控制对象的创建过程,适合创建复杂对象。
  • 支持不可变对象:可以构建不可变对象,增强对象的安全性。

缺点

  • 增加系统复杂度:需要为每个产品定义建造者接口和多个具体建造者类。
  • 不适合简单对象:对于简单对象,使用建造者模式会增加不必要的复杂度。
  • 客户端依赖建造者:客户端代码需要了解具体的建造者类,增加了耦合度。

扩展

  • 链式调用:通过返回 this 支持链式调用,使 API 更加简洁。
  • 建造者与工厂结合:使用工厂模式管理建造者的创建和选择。
  • 建造不可变对象:通过建造者一次性构建对象,避免暴露 setter 方法。
  • 默认值设置:可以在建造者中预设默认值,简化对象创建过程。

模式协作

  • 与工厂模式结合:建造者模式可以和工厂模式结合使用,工厂用于创建建造者实例。
  • 与单例模式结合:建造者或指挥者可以作为单例存在,提高性能。
  • 与原型模式结合:可以通过原型模式复制已有对象的结构,再使用建造者进行定制。
  • 与装饰者模式结合:建造者可以用于构建装饰器链。

延伸思考

  • 链式调用与 Fluent API:现代开发中,建造者常用于构建 Fluent API。
  • Java 中的 Lombok:Lombok 的 @Builder 注解简化了建造者模式的实现。
  • 不可变对象的构建:建造者模式是构建复杂不可变对象的理想选择。
  • 构建器模式在 JSON 序列化中的应用:如 Jackson、Gson 等库内部使用建造者模式构建复杂对象。

总结

建造者模式是一种强大的创建型设计模式,适用于创建复杂对象的场景。它通过将对象的构建过程与表示分离,提升了代码的灵活性和可维护性。无论是在 Java 还是 PHP 中,建造者模式都提供了良好的实践方式。通过与工厂、单例等模式结合,建造者模式可以适应更复杂的构建需求。在实际开发中,合理使用建造者模式可以大大提升代码质量。