目录
模板方法模式是一种行为型设计模式,它定义了一个算法的骨架,并将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。这种模式常用于封装算法的框架,其中某些步骤是固定的,而某些步骤则需要具体实现。
模板方法模式的关键概念
- 算法骨架:定义算法的基本步骤。
- 抽象方法:由子类实现的方法,代表算法中的可变部分。
- 钩子方法:提供子类扩展点的方法,通常不强制子类实现。
- 具体方法:已实现的方法,代表算法中的不变部分。
1. 算法骨架(Algorithm Skeleton)
算法骨架是指模板方法模式中定义的一个算法的基本步骤或流程。这些步骤通常是算法的核心部分,定义了算法的执行顺序。算法骨架通常在基类(抽象类或具体类)中定义,它通过一个或多个最终方法(final method)来实现。这些方法通常包含算法的固定部分,同时也包含对抽象方法的调用,这些抽象方法将在子类中具体实现。
2. 抽象方法(Abstract Methods)
抽象方法是由子类实现的方法,代表算法中的可变部分。这些方法在基类中声明为抽象方法,没有具体的实现。子类必须提供这些方法的具体实现。通过这种方式,子类可以控制算法的某些具体细节,同时保持算法整体结构的一致性。
3. 钩子方法(Hook Methods)
钩子方法是在基类中提供的扩展点,通常不强制子类实现。钩子方法允许子类在特定时刻扩展算法的行为,而不会破坏算法的整体结构。钩子方法通常是可选的,子类可以选择实现它们,也可以选择不实现。钩子方法可以用来控制算法的某些特定阶段是否执行某些操作。
4. 具体方法(Concrete Methods)
具体方法是指在基类中已经实现的方法,代表算法中的不变部分。这些方法在算法的所有实现中都是相同的,不需要子类重新定义。具体方法提供了算法的一部分固定实现,使得子类只需要关注那些需要变化的部分。
适用场景
模板方法模式适用于以下情况:
- 一个算法具有相同的步骤,但某些步骤的具体实现因环境而异。
- 封装不变的部分,开放可变的部分。
- 控制子类扩展,即子类只能覆盖某些特定的方法。
示例:制作饮品
假设我们需要制作不同种类的饮品(如茶和咖啡),这些饮品的制作过程基本相同,但在某些步骤上有所区别。例如,制作茶和咖啡都需要加水、冲泡、倒入杯子,但具体的冲泡方式和添加的调料可能不同。这里可以使用模板方法模式来定义一个通用的制作饮品的框架,并允许子类实现特定的步骤。
示例代码
java
深色版本
1// 抽象类:定义了制作饮品的基本框架
2abstract class Beverage {
3 // 定义算法的骨架
4 public final void prepareRecipe() {
5 boilWater();
6 brew();
7 pourInCup();
8 addCondiments();
9 }
10
11 // 具体方法:不变的部分
12 protected void boilWater() {
13 System.out.println("Boiling water");
14 }
15
16 protected void pourInCup() {
17 System.out.println("Pouring into cup");
18 }
19
20 // 抽象方法:需要子类实现的部分
21 protected abstract void brew();
22
23 protected abstract void addCondiments();
24
25 // 钩子方法:提供扩展点
26 protected boolean customerWantsCondiments() {
27 return true;
28 }
29}
30
31// 具体子类:茶
32class Tea extends Beverage {
33 @Override
34 protected void brew() {
35 System.out.println("Steeping the tea");
36 }
37
38 @Override
39 protected void addCondiments() {
40 if (customerWantsCondiments()) {
41 System.out.println("Adding lemon");
42 }
43 }
44}
45
46// 具体子类:咖啡
47class Coffee extends Beverage {
48 @Override
49 protected void brew() {
50 System.out.println("Dripping coffee through filter");
51 }
52
53 @Override
54 protected void addCondiments() {
55 if (customerWantsCondiments()) {
56 System.out.println("Adding sugar and milk");
57 }
58 }
59}
60
61// 客户端代码
62public class Main {
63 public static void main(String[] args) {
64 Beverage tea = new Tea();
65 tea.prepareRecipe();
66
67 System.out.println("------------------------");
68
69 Beverage coffee = new Coffee();
70 coffee.prepareRecipe();
71 }
72}
解释
-
抽象类
Beverage
:定义了制作饮品的基本框架。它包含了一个最终方法prepareRecipe()
,这是算法的骨架,定义了制作饮品的步骤。它还包含了一些具体方法(如boilWater()
和pourInCup()
),这些方法对于所有子类都是相同的。 -
抽象方法:
brew()
和addCondiments()
是抽象方法,由子类实现。这些方法代表了算法中可变的部分。 -
钩子方法:
customerWantsCondiments()
是一个钩子方法,允许子类在特定条件下扩展行为。如果客户不需要调料,子类可以选择不调用addCondiments()
方法。 -
具体子类:
Tea
和Coffee
分别实现了brew()
和addCondiments()
方法,以适应各自的需求。
输出结果
plaintext
深色版本
1Boiling water
2Steeping the tea
3Pouring into cup
4Adding lemon
5------------------------
6Boiling water
7Dripping coffee through filter
8Pouring into cup
9Adding sugar and milk
总结
模板方法模式通过定义一个算法的骨架,并将某些步骤留给子类实现,使得子类可以在不改变算法结构的情况下重新定义这些步骤。这有助于减少代码重复,并提高代码的可维护性和扩展性。