概念

建造者模式(Builder Pattern)是一种创建型设计模式,它将一个复杂对象的构建过程与其表示分离,使得同样的构建过程可以创建不同的表示

建造者模式通过引入一个建造者接口和具体建造者实现类来实现这一点


在建造者模式中,通常存在四个核心角色:产品(Product)、建造者(Builder)、具体建造者(Concrete Builder)和指挥者(Director)

产品是最终要构建的复杂对象,建造者定义了构建产品所需的步骤和方法,具体建造者实现了建造者接口,负责实际构建产品的过程,而指挥者负责指导构建过程的顺序和调用具体建造者的方法来构建产品


建造者模式的核心思想是将一个复杂对象的构建过程分解成多个简单的步骤,然后由具体建造者来逐步构建产品的各个部分,最终组装成完整的产品

这种分离使得同样的构建过程可以创建不同的表示,使得系统更加灵活、可维护和可扩展

建造者模式适用于以下情况:

  1. 构建过程需要多个步骤或者需要根据不同的条件来构建不同的产品
  2. 需要控制产品的构建过程,以及灵活地组合各个部分


举个简单的例子,考虑一个汽车制造过程

汽车有多个部件(如车轮、发动机、车身等),而不同型号的汽车可能需要不同配置的部件

使用建造者模式,可以将汽车的制造过程分解成多个步骤,每个步骤由具体建造者来实现,从而实现了不同型号汽车的定制化生产


实现条件

  1. 当一个对象的构建过程复杂时,例如对象由多个部分组成,且对象的创建需要按照特定的顺序或流程
  2. 当需要提供一个清晰的对象构建API,隐藏对象的内部表示和构建过程
  3. 当对象需要有不同的表示形式,且需要允许外部代码在不同表示之间进行切换


实现的方式

在JavaScript中,建造者模式可以通过多种方式实现:

  1. 链式调用(Fluent Interface)

    通过在建造者的每个设置方法末尾返回 this 实现链式调用

  2. 独立的Builder类

    创建一个单独的Builder类,专门负责构造复杂对象

  3. 使用函数参数

    使用配置对象作为函数参数,内部通过一系列操作构建最终对象

  4. 分步骤构建

    将对象的构建分解为多个不同的步骤,每个步骤负责构建对象的一部分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
class Car {
constructor(make, model, color) {
this.make = make
this.model = model
this.color = color
// 更多属性...
}

// ... 其他方法 ...
}

class CarBuilder {
constructor() {
this.car = new Car()
}

setMake(make) {
this.car.make = make
return this
}

setModel(model) {
this.car.model = model
return this
}

setColor(color) {
this.car.color = color
return this
}

// ... 其他设置方法 ...

build() {
return this.car
}
}

// 使用建造者
const carBuilder = new CarBuilder()
const car = carBuilder.setMake('Audi').setModel('A4').setColor('blue').build()


场景

  • SQL查询构建器(如 Knex.js

    允许通过链式方法构建SQL查询

  • HTTP请求库(如 AxiosRequest

    提供了一个流畅的API来构建HTTP请求

  • UI库(如 Vue.js 的组件构建过程)

    使用了类似建造者的模式来构建和配置组件

建造者模式的主要优势是提高了代码的可读性和可维护性,特别是在构建复杂对象时

通过逐步构建对象,并且可以随时改变对象的状态,可以使代码更加灵活和易于理解

[!Important]

直接把参数都传入进去不就好了?为什么要分步骤设置

直接将所有参数传入构造函数确实是一种可行的方法,特别是在对象结构简单或者参数数量较少时。然而,建造者模式的优势在于它提供了一种更灵活、更清晰的方式来构建复杂对象,尤其是在以下情况下:

  1. 增强可读性

    当创建一个包含多个属性的对象时,直接传递一个包含大量参数的构造函数可能会降低代码的可读性。使用建造者模式,每个步骤的方法名可以清晰地表达正在设置的属性,使得代码更易于理解

  2. 可选参数和默认值

    在创建对象时,可能有一些属性是可选的,或者可以有默认值。建造者模式允许你只设置那些需要被覆盖的属性,而不必为每个属性提供一个参数

  3. 不变性

    一旦对象被构建,它就可以是不可变的。这意味着,创建对象后,就不能再更改它的状态。这在多线程环境中是非常有用的,因为它避免了状态同步问题

  4. 灵活的构造过程

    如果对象的构建过程涉及多个步骤,这些步骤可能会根据特定的逻辑或条件而变化,建造者模式允许你控制这个过程,而不是一次性地提供所有数据

  5. 复杂对象的构建

    对于复杂对象,可能需要执行额外的逻辑来正确地初始化对象的状态。建造者模式提供了一个中心位置来包含这种逻辑,而不是将它分散在应用程序的多个位置

  6. 构建对象的不同表示

    如果你需要根据不同的配置或条件构建多种不同的对象表示,建造者模式可以使这一过程更加直接和清晰

  7. 链式调用

    建造者模式允许链式调用,这使得构建指令更加流畅。这在函数式编程中很常见,可以提高代码的表现力

举一个简单的例子,如果你正在创建一个配置复杂的图表对象,你可能需要设置数据源、图表类型、颜色主题、标题、图例以及其他许多配置项

如果你的构造函数接受所有这些作为参数,调用它会变得非常复杂

但是,如果你使用建造者模式,你可以逐步设置这些属性,并且在每个步骤中都可以应用特定的逻辑或验证

总的来说,建造者模式并不是在所有情况下都是必要的,但对于复杂对象的构建,它提供了一种更加灵活和清晰的方法


源代码