模板方法模式
# 模板方法模式
模板方法(算法骨架),通过抽象类定义共性的方法,特性的方法通过抽象方法表示,通过不同的子类实现差异化。
# 定义
模板方法模式,在一个方法中定义一个算法的骨架,而将一些步骤的实现延迟到子类中,使得子类可以在不改变一个算法的结构前提下即可重定义该算法的某些特定步骤。
- img: https://bitouyun.com/images/design-pattern/template.png
link: https://bitouyun.com/images/design-pattern/template.png
name: 模板方法模式
1
2
3
2
3
模板方法模式是基于继承的代码复用基本技术,在模板方法模式中,可以将相同的代码放在父类中,而将不同的方法实现放在不同的子类中。
模板方法中可以通过钩子函数增加灵活性,它在抽象类中不做事,或者是默认的事情,子类可以选择覆盖它。
一般模板方法都加上final关键字, 防止子类重写模板方法。
模板方法模式有两大作用:复用和扩展。其中复用指的是,所有的子类可以复用父类中提供的模板方法的代码。扩展指的是,框架通过模板模式提供功能扩展点,让框架用户可以在不修改框架源码的情况下,基于扩展点定制化框架的功能。
# 优点
封装了不变部分,扩展可变部分。
提取了公共的部分代码,便于代码复用。
通过增加子类可以很好的扩展算法,符合开闭原则。
# 缺点
对于不同的实现都需要增加一个子类,这会导致系统的类增多。
通过子类方法影响父类方法,这导致一种反向的控制结构,它提高了代码阅读的难度。
基于继承关系自身的特点,父类添加新的抽象方法,所有子类都需要同步修改一遍,增加维护成本。
# 应用场景
当要完成在某个过程,该过程要执行一系列步骤 ,这一系列的步骤基本相同,但其个别步骤在实现时可能不同,通常考虑用模板方法模式来处理。
# 示例代码
场景
去银行办理取钱、开卡业务需要以下步骤:1、取号 2、办业务 3、评价。
办理的业务不同,有不同的业务实现,特殊情况,如:VIP客户取钱不需要排队取号,可以用钩子方法由子类决定是否执行取号业务。
/**
* 抽象类
* 定义一个业务的骨架,共用业务的默认实现
*/
public abstract class BankBusinessHandler {
/**
* 模板方法,final防止子类重写该方法
*/
public final void execute() {
if (!isVip()) {
getNumber(); // 非VIP,先取号
}
handle(); // 办理业务
judge(); // 评价
}
/**
* 是否VIP
* 抽象方法,由子类实现
*/
public abstract boolean isVip();
/**
* 取号业务
*/
private void getNumber() {
System.out.println("号码:" + new Random().nextInt());
}
/**
* 办理业务
* 抽象方法,由子类实现
*/
public abstract void handle();
/**
* 评价业务
*/
private void judge() {
System.out.println("评价");
}
}
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
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
/**
* 取钱业务
*/
public class GetMoneyHandler extends BankBusinessHandler {
@Override
public boolean isVip() {
// VIP取钱不需要取号
return true;
}
@Override
public void handle() {
System.out.println("取钱业务");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
* 开卡业务
*/
public class OpenCardHandler extends BankBusinessHandler {
@Override
public boolean isVip() {
return false;
}
@Override
public void handle() {
System.out.println("开通银行卡");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Client {
public static void main(String[] args) {
BankBusinessHandler getMoneyHandler = new GetMoneyHandler();
getMoneyHandler.execute(); // 取钱业务 评价
BankBusinessHandler openCardHandler = new OpenCardHandler();
openCardHandler.execute(); // 号码:15627027 开通银行卡 评价
}
}
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
// Make sure to add code blocks to your code group
上次更新: 2023/11/17, 09:38:49