初识设计模式——建造者模式(Builder Pattern)

cuixiaogang

建造者模式(Builder Pattern)是一种创建型设计模式,它将一个复杂对象的构建与表示分离,使得同样的构建过程可以创建不同的表示。该模式允许你逐步构建一个复杂对象,通过使用多个简单的步骤来创建最终对象,而不是一次性构建整个对象。

建造者模式的构成

  • 产品(Product):要构建的复杂对象。
  • 抽象建造者(Abstract Builder):定义了构建产品各个部分的抽象接口。
  • 具体建造者(Concrete Builder):实现了抽象建造者接口,负责具体的构建过程。
  • 指挥者(Director):负责安排复杂对象的构建步骤,它调用建造者的方法来完成对象的构建。

建造者模式结构图

案例

场景

在 Web 开发中,表单构建是一个常见的使用建造者模式的场景。假设我们要构建一个复杂的表单,表单包含不同类型的输入元素(如文本框、下拉框、单选框等),并且可以根据不同的需求构建不同样式和功能的表单。

代码

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
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
<?php
// 产品类:表单
class Form {
private $elements = [];

public function addElement($element) {
$this->elements[] = $element;
}

public function render() {
$form = '<form>';
foreach ($this->elements as $element) {
$form .= $element;
}
$form .= '</form>';
return $form;
}
}

// 抽象建造者类
abstract class FormBuilder {
protected $form;

public function __construct() {
$this->form = new Form();
}

abstract public function buildTextInput($name, $label);
abstract public function buildSelect($name, $label, $options);
abstract public function buildRadioGroup($name, $label, $options);

public function getForm() {
return $this->form;
}
}

// 具体建造者类:简单表单建造者
class SimpleFormBuilder extends FormBuilder {
public function buildTextInput($name, $label) {
$element = "<label for='{$name}'>{$label}</label>";
$element .= "<input type='text' id='{$name}' name='{$name}'>";
$this->form->addElement($element);
}

public function buildSelect($name, $label, $options) {
$element = "<label for='{$name}'>{$label}</label>";
$element .= "<select id='{$name}' name='{$name}'>";
foreach ($options as $value => $text) {
$element .= "<option value='{$value}'>{$text}</option>";
}
$element .= "</select>";
$this->form->addElement($element);
}

public function buildRadioGroup($name, $label, $options) {
$element = "<label>{$label}</label>";
foreach ($options as $value => $text) {
$element .= "<input type='radio' id='{$name}_{$value}' name='{$name}' value='{$value}'>";
$element .= "<label for='{$name}_{$value}'>{$text}</label>";
}
$this->form->addElement($element);
}
}

// 指挥者类
class FormDirector {
private $builder;

public function __construct(FormBuilder $builder) {
$this->builder = $builder;
}

public function constructForm() {
$this->builder->buildTextInput('username', '用户名');
$this->builder->buildSelect('gender', '性别', ['male' => '男', 'female' => '女']);
$this->builder->buildRadioGroup('age_group', '年龄组', ['18-25' => '18 - 25岁', '26-35' => '26 - 35岁']);
return $this->builder->getForm();
}
}

// 客户端代码
$simpleBuilder = new SimpleFormBuilder();
$director = new FormDirector($simpleBuilder);
$form = $director->constructForm();
echo $form->render();

代码解释

  • 产品类 Form:表示最终要构建的表单,它包含一个元素数组 $elements,可以添加不同的表单元素,并提供 render 方法将表单元素组合成完整的 HTML 表单。
  • 抽象建造者类 FormBuilder:定义了构建不同类型表单元素的抽象方法,如 buildTextInput、buildSelect 和 buildRadioGroup,并提供了获取最终表单的方法 getForm。
  • 具体建造者类 SimpleFormBuilder:实现了抽象建造者类的方法,具体负责构建不同类型的表单元素,并将其添加到表单中。
  • 指挥者类 FormDirector:负责安排表单的构建步骤,调用建造者的方法来构建表单。
  • 客户端代码:创建具体建造者和指挥者对象,调用指挥者的 constructForm 方法构建表单,并调用表单的 render 方法输出最终的 HTML 表单。

UML类图

UML类图

建造者模式的优缺点

优点

  • 解耦构建过程和表示:将对象的构建过程和表示分离,使得构建过程可以独立变化,不同的构建者可以创建不同的表示。
  • 便于控制构建过程:通过指挥者可以精确控制对象的构建步骤,使得构建过程更加清晰和可维护。
  • 提高代码复用性:具体建造者可以被多个指挥者复用,提高了代码的复用性。

缺点

  • 代码复杂度增加:建造者模式需要定义多个类和接口,会增加代码的复杂度,特别是对于简单对象的构建,可能会显得过于繁琐。
  • 建造者和产品之间的耦合度较高:建造者模式中,建造者类通常需要知道产品的具体实现细节,这会导致建造者和产品之间的耦合度较高。

建造者模式的适用场景

  • 对象的构建过程复杂:当一个对象的构建过程包含多个步骤,且这些步骤的顺序和组合可能会发生变化时,可以使用建造者模式。
  • 需要创建不同表示的对象:当需要创建具有不同表示的对象时,可以使用不同的具体建造者来实现。
  • 构建过程需要独立于表示:当构建过程需要独立于对象的表示时,可以使用建造者模式将构建过程和表示分离。