设计模式之行为型设计模式-模板方法模式

1. 模式简介

定义一个程序的整体流程,并允许子类为其中的一个或者多个步骤提供具体实现。模板方法使得子类可以在不改变整体流程的情况下,重新定义其中的某些步骤。属于行为型设计模式

2. 示例代码

这里我们通过模板方法模式实现一个短信发送、邮件发送的 demo。

  • 定义一个整体流程
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
/**
* <p>
* 消息发送器
* </p>
*
* @author yangkai.shen
* @date Created in 2019/11/18 17:22
*/
public abstract class BaseMessageSender {
/**
* 发送消息
*
* @param content 内容
*/
public void send(String content) {
validate(content);
if (!execute(content)) {
error(content);
}
}

/**
* 校验消息
*
* @param content 数据
*/
protected abstract void validate(String content);

/**
* 发送消息
*
* @param content 数据
* @return {@code true} - 发送成功,{@code false} - 发送失败
*/
protected abstract boolean execute(String content);

/**
* 错误记录
*
* @param content 数据
*/
protected abstract void error(String content);
}
  • 短信发送的具体实现
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
/**
* <p>
* 短信发送器
* </p>
*
* @author yangkai.shen
* @date Created in 2019/11/18 17:40
*/
public class SmsSender extends BaseMessageSender {
/**
* 校验消息
*
* @param content 数据
*/
@Override
protected void validate(String content) {
if (content == null || "".equals(content.trim()) || content.trim().length() != 11) {
throw new RuntimeException("手机号码不合法");
}
}

/**
* 发送消息
*
* @param content 数据
* @return {@code true} - 发送成功,{@code false} - 发送失败
*/
@Override
protected boolean execute(String content) {
Random random = new Random();
if (random.nextInt(10) % 2 == 0) {
System.out.println("短信发送成功!");
return true;
} else {
return false;
}
}

/**
* 错误记录
*
* @param content 数据
*/
@Override
protected void error(String content) {
System.err.println("短信发送失败!手机号:" + content);
}
}
  • 邮件发送的具体实现
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
/**
* <p>
* 邮件发送器
* </p>
*
* @author yangkai.shen
* @date Created in 2019/11/18 17:34
*/
public class EmailSender extends BaseMessageSender {
/**
* 校验消息
*
* @param content 数据
*/
@Override
protected void validate(String content) {
if (content == null || "".equals(content.trim())) {
throw new RuntimeException("数据不能为空");
}
}

/**
* 发送消息
*
* @param content 数据
* @return {@code true} - 发送成功,{@code false} - 发送失败
*/
@Override
protected boolean execute(String content) {
Random random = new Random();
if (random.nextInt(10) % 2 == 0) {
System.out.println("邮件发送成功!");
return true;
} else {
return false;
}
}

/**
* 错误记录
*
* @param content 数据
*/
@Override
protected void error(String content) {
System.err.println("邮件发送失败!发送内容:" + content);
}
}
  • 测试类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/**
* <p>
* 模板模式,测试类
* </p>
*
* @author yangkai.shen
* @date Created in 2019/11/18 17:10
*/
public class PatternTest {
public static void main(String[] args) {
// 邮件发送
EmailSender emailSender = new EmailSender();
emailSender.send("测试内容");

// 短信发送
SmsSender smsSender = new SmsSender();
smsSender.send("17312341234");
}
}
  • 测试结果
1
2
邮件发送失败!发送内容:测试内容
短信发送成功!

3. UML 图例

design-pattern-template-uml

4. 应用

1
2
3
// Spring Data 这个模块下存在特别多的应用
// 比如:
// JdbcTemplate、RedisTemplate、MongoTemplate、ElasticsearchTemplate

5. 场景

  • 一次性实现一个算法的主体流程的部分,并将可变的行为留给子类来实现。

  • 各子类中公共的行为被提取出来并集中到一个公共的父类中,从而避免代码重复。

6. 优缺点

优点: 1、提高代码的复用性。2、提高代码的扩展性。3、符合开闭原则。

缺点: 1、导致类的数目增加。2、间接地增加了系统实现的复杂度。3、继承关系存在自身缺点,如果父类添加了新的抽象方法,所有子类都需要重新改一遍。

7. 完整代码地址

https://github.com/xkcoding/design-pattern/tree/master/src/main/java/com/xkcoding/design/pattern/behavioral/template

-------------本文结束  感谢您的阅读-------------
xkcoding wechat
欢迎来我的公众号「xkcoding小凯扣丁」逛逛
o(╯□╰)o 赞助一杯咖啡 ~~