建造者模式
引言
在软件开发中,我们常常会遇到一些复杂的对象,它们通常由多个部分组成,并且这些部分之间有复杂的依赖关系。如果我们直接使用构造方法或者工厂模式来创建这些对象,代码将变得冗长且难以维护。为了解决这个问题,建造者模式(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 中,建造者模式都提供了良好的实践方式。通过与工厂、单例等模式结合,建造者模式可以适应更复杂的构建需求。在实际开发中,合理使用建造者模式可以大大提升代码质量。