GoF设计模式(二十三):Template Pattern 模板模式

模板模式,作为常用的典型的代码复用技术,其同样是一种行为型的设计模式

abstract.jpeg

模式思想

使用过JDBC来操作数据库的朋友,应该对那套操作流程非常熟悉:连接数据库、打开数据库、执行SQL语句、关闭数据库。但如果每次都写一大堆重复的代码而仅仅只是为了执行一个SQL语句,显然显得很啰嗦。而且事实上对于各种不同的数据库,比如MySQL、DB2、Oracle等等,基本的操作流程也是差不多的。历史经验告诉我们,重复的、冗余的代码具备可优化、可复用的潜能。这里为了复用上述场景的重复代码,我们来介绍一种新的设计模式——Template Pattern 模板模式

在模板模式下,其只有两个角色

  • 抽象模板角色:该角色中会定义若个抽象方法,以便让不同的具体模板角色去实现。与此同时,其还会提供一些具体方法,在该方法中其规定了若干个抽象方法调用的逻辑顺序,此方法即为所谓的模板方法。可以看到,其是对之前代码中重复的调用逻辑的复用和组合。即本文的DatabaseTemplate数据库模板类
  • 具体模板角色:其是对抽象模板角色的具体实现。其提供了对抽象模板角色的抽象方法的具体实现。即本文的MySQL数据库模板MySQLTemplate类、DB2数据库模板DB2Template类、Oracle数据库模板OracleTemplate类

实现

现在通过Java来实现上面的例子。首先定义一个抽象模板角色,即DatabaseTemplate数据库模板类。可以看到其定义了操作各类型数据库的通用方法接口。与此同时还提供一个模板方法,其中规定了操作各数据库时的相关顺序逻辑。这里为了保证具体模板角色不对其进行重写,故使用了final进行修饰

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
/**
* 抽象模板角色: 数据库模板
*/
public abstract class DatabaseTemplate {
/**
* 通过SQL语句来使用数据库
* @param sql
* @apiNote
* 1. 其是一个模板方法, 用于规定各方法的调用顺序
* 2. 使用final进行修饰, 保证子类无法重写该方法
*/
public final void useDatabase(String sql) {
connectionDatabase();
openDatabase();
execSql(sql);
closeDatabase();
}

/**
* 连接数据库
*/
public abstract void connectionDatabase();

/**
* 打开数据库
*/
public abstract void openDatabase();

/**
* 执行SQL语句
* @param sql
*/
public abstract void execSql(String sql);

/**
* 关闭数据库
*/
public abstract void closeDatabase();
}

现在,只需为各类型的数据库提供相应的具体模板类即可

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
72
73
74
/**
* 具体模板角色: MySQL数据库模板
*/
public class MySQLTemplate extends DatabaseTemplate {
@Override
public void connectionDatabase() {
System.out.println("连接 MySQL 数据库");
}

@Override
public void openDatabase() {
System.out.println("打开 MySQL 数据库");
}

@Override
public void execSql(String sql) {
System.out.println("执行SQL语句: " + sql);
}

@Override
public void closeDatabase() {
System.out.println("关闭 MySQL 数据库");
}
}
...
/**
* 具体模板角色: DB2数据库模板
*/
public class DB2Template extends DatabaseTemplate {
@Override
public void connectionDatabase() {
System.out.println("连接 DB2 数据库");
}

@Override
public void openDatabase() {
System.out.println("打开 DB2 数据库");
}

@Override
public void execSql(String sql) {
System.out.println("执行SQL语句: " + sql);
}

@Override
public void closeDatabase() {
System.out.println("关闭 DB2 数据库");
}
}
...
/**
* 具体模板角色: Oracle数据库模板
*/
public class OracleTemplate extends DatabaseTemplate {
@Override
public void connectionDatabase() {
System.out.println("连接 Oracle 数据库");
}

@Override
public void openDatabase() {
System.out.println("打开 Oracle 数据库");
}

@Override
public void execSql(String sql) {
System.out.println("执行SQL语句: " + sql);
}

@Override
public void closeDatabase() {
System.out.println("关闭 Oracle 数据库");
}
}

现在,client操作各数据库时再也不写一大堆重复的代码了(连接数据库、打开数据库、执行SQL语句、关闭数据库)。而只需要获取相应的数据库模板实例进行操作即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/**
* Template Pattern 模板模式 Demo
*/
public class TemplatePatternDemo {
public static void main(String[] args) {
System.out.println("----------------- Test 1 -----------------");
MySQLTemplate mySQLTemplate = new MySQLTemplate();
String sql1 = "drop table user_token";
mySQLTemplate.useDatabase(sql1);

System.out.println("\n----------------- Test 2 -----------------");
DB2Template db2Template = new DB2Template();
String sql2 = "select * from user_info";
db2Template.useDatabase(sql2);

System.out.println("\n----------------- Test 3 -----------------");
OracleTemplate oracleTemplate = new OracleTemplate();
String sql3 = "select * from system_log";
oracleTemplate.useDatabase(sql3);
}
}

测试结果如下,符合预期

figure 1.jpeg

参考文献

  1. Head First 设计模式 弗里曼著
  2. 图解设计模式 结城浩著
0%