模板方法模式
# 模板方法模式
# 一、模板方法模式
原理:模板方法模式是一种行为设计模式, 它在超类中定义了一个算法的框架, 允许子类在不修改结构的情况下重写算法的特定步骤。
优缺点
- 1 优点
- 代码复用:通过将通用的行为提取到基类中,减少了代码的重复,提高了代码的复用性。
- 遵循开闭原则:通过增加新的子类,能够很方便地扩展算法,而无需修改现有代码。
- 让子类实现具体步骤:子类可以实现算法的特定步骤,从而增加了灵活性。
- 代码组织清晰:将算法的框架与具体实现分开,使代码更清晰、更易维护。
- 控制反转:模板方法模式利用了控制反转的设计思想,即父类控制子类的行为,通过在父类中定义算法框架来约束子类的行为。
- 2 缺点
- 类数量增加:每个不同的实现都需要一个新的子类,可能会导致类的数量增加,从而增加系统的复杂性。
- 难以维护:如果算法骨架发生变化,需要修改基类和所有子类,维护起来可能比较麻烦。
- 灵活性受到限制:子类必须遵循父类定义的算法框架,灵活性受到一定限制。
- 继承的缺点:由于使用了继承,子类与基类之间耦合度高,如果基类发生变化,子类也需要做相应修改。
适用场景
- 具有稳定的算法框架:算法的整体步骤是固定的,但某些步骤的实现可以有不同方式。
- 多个子类有公共行为:多个子类需要重复执行某些相同的行为,这些行为可以提取到基类中。
- 需要控制子类的扩展:通过模板方法模式,可以控制子类的行为,使其在一个确定的框架内进行扩展。
# 二、模板方法模式基本代码
模板方法抽象类
abstract class AbstractClass { // 模板方法,定义算法的骨架 public final void templateMethod() { stepOne(); stepTwo(); stepThree(); } // 基本方法(由子类实现) protected abstract void stepOne(); protected abstract void stepTwo(); protected abstract void stepThree(); }
1
2
3
4
5
6
7
8
9
10
11
12
13
14具体模板类A,B
class ConcreteClassA extends AbstractClass { @Override protected void stepOne() { System.out.println("ConcreteClassA: Step One"); } @Override protected void stepTwo() { System.out.println("ConcreteClassA: Step Two"); } @Override protected void stepThree() { System.out.println("ConcreteClassA: Step Three"); } } class ConcreteClassB extends AbstractClass { @Override protected void stepOne() { System.out.println("ConcreteClassB: Step One"); } @Override protected void stepTwo() { System.out.println("ConcreteClassB: Step Two"); } @Override protected void stepThree() { System.out.println("ConcreteClassB: Step Three"); } }
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客户端
public class TemplateMethodPatternDemo { public static void main(String[] args) { AbstractClass classA = new ConcreteClassA(); classA.templateMethod(); AbstractClass classB = new ConcreteClassB(); classB.templateMethod(); } }
1
2
3
4
5
6
7
8
9
# 三、实现方式
分析目标算法, 确定能否将其分解为多个步骤。 从所有子类的角度出发, 考虑哪些步骤能够通用, 哪些步骤各不相同。
创建抽象基类并声明一个模板方法和代表算法步骤的一系列抽象方法。 在模板方法中根据算法结构依次调用相应步骤。 可用
final
最终修饰模板方法以防止子类对其进行重写。虽然可将所有步骤全都设为抽象类型, 但默认实现可能会给部分步骤带来好处, 因为子类无需实现那些方法。
可考虑在算法的关键步骤之间添加钩子。
为每个算法变体新建一个具体子类, 它必须实现所有的抽象步骤, 也可以重写部分可选步骤。
编辑 (opens new window)