初识设计模式——模板模式(Template Pattern)

cuixiaogang

模板模式(Template Pattern)是一种行为设计模式,它定义了一个算法的骨架,将一些步骤的实现延迟到子类中。这样,在不改变算法结构的前提下,子类可以重新定义算法中的某些步骤。模板模式通过抽象类和具体子类的协作,实现了代码的复用和扩展。

模板模式的结构

  • 抽象类(Abstract Class):定义了算法的骨架,包含了一系列抽象方法和具体方法。抽象方法由子类实现,具体方法则提供了算法的默认实现或公共逻辑。
  • 具体子类(Concrete Class):继承自抽象类,实现了抽象类中的抽象方法,完成算法中特定步骤的具体实现。

模板模式结构图

代码案例

场景

假设我们要实现一个制作饮料的过程,不同的饮料制作过程有一些共同的步骤,也有一些不同的步骤。

代码

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
<?php
// 抽象类:饮料制作模板
abstract class BeverageMaker {
// 模板方法,定义了制作饮料的算法骨架
public final function prepareBeverage() {
$this->boilWater();
$this->brew();
$this->pourInCup();
if ($this->customerWantsCondiments()) {
$this->addCondiments();
}
}

// 具体方法:烧水
protected function boilWater() {
echo "Boiling water\n";
}

// 抽象方法:冲泡
abstract protected function brew();

// 具体方法:倒入杯子
protected function pourInCup() {
echo "Pouring into cup\n";
}

// 抽象方法:添加调料
abstract protected function addCondiments();

// 钩子方法:默认返回 true,子类可以重写
protected function customerWantsCondiments() {
return true;
}
}

// 具体子类:咖啡制作
class CoffeeMaker extends BeverageMaker {
protected function brew() {
echo "Dripping coffee through filter\n";
}

protected function addCondiments() {
echo "Adding sugar and milk\n";
}

protected function customerWantsCondiments() {
// 可以根据具体情况决定是否添加调料
return false;
}
}

// 具体子类:茶制作
class TeaMaker extends BeverageMaker {
protected function brew() {
echo "Steeping the tea\n";
}

protected function addCondiments() {
echo "Adding lemon\n";
}
}

// 使用示例
$coffeeMaker = new CoffeeMaker();
$coffeeMaker->prepareBeverage();

echo "\n";

$teaMaker = new TeaMaker();
$teaMaker->prepareBeverage();
?>

UML类图

UML类图

模板模式的优缺点

优点

  • 代码复用:将算法的公共部分提取到抽象类中,避免了代码的重复编写,提高了代码的复用性。
  • 可扩展性:子类可以通过实现抽象方法来改变算法的某些步骤,而不影响算法的整体结构,增强了系统的可扩展性。
  • 便于维护:算法的骨架在抽象类中定义,使得代码的结构更加清晰,便于维护和修改。

缺点

  • 子类数量增加:如果算法的步骤较多,可能会导致子类的数量增加,使得代码的复杂度提高。
  • 违反开闭原则:如果需要修改算法的骨架,可能会影响到所有的子类,违反了开闭原则。

模板模式的适用场景

  • 算法骨架固定:当多个算法具有相同的骨架,但某些步骤的实现不同时,可以使用模板模式。例如,数据库操作的增删改查、文件处理的读取和写入等。
  • 代码复用:当多个类中有一些公共的行为或步骤时,可以将这些公共部分提取到抽象类中,实现代码的复用。
  • 框架设计:在框架设计中,模板模式经常用于定义框架的基本流程,让开发者通过实现特定的方法来定制框架的行为。例如,Web 框架中的控制器基类、测试框架中的测试用例基类等。