“ 模版方法模式定义一个操作中的算法框架,而将一些步骤延迟到子类中,使得子类可以不改变一个算法的结构即可定义该算法的某些特定步骤”
在前面我们聊过适配器模式,回调模式,策略模式。其中适配器模式是结构型设计模式,它的设计是为了适应两个原本不兼容的接口而诞生的设计模式。回调模式不属于23种设计模式,它指得是通过函数参数传递到其它代码的,某一块可执行代码的引用。这一设计允许了底层代码调用在高层定义的子程序。而策略模式属于行为型设计模式,它是用来识别对象之间的常用交流模式并加以实现(也就是使得接口独立于使用它的客户端而独自改变)。今天仍然学习一下属于行为型设计模式的,模版方法模式。
案例
模版方法模式定义一个操作中的算法框架,而将一些步骤延迟到子类中,使得子类可以不改变一个算法的结构即可冲定义该算法的某些特定步骤。什么意思呢?将一些步骤延迟到子类中,可以理解为实现的细节放入到子类中,而整个实现过程在模版方法中早已定义好。
在最初学习数据的时候,你还记得有哪几步吗?
1. 加载驱动
2. 建立连接
3. 获取Statement
4. 拼接参数(针对PreparedStatement)
5. 执行
6. 返回结果
7. 销毁连接
写了一个连接代码:
// JDBC 驱动名及数据库 URL
static final String JDBC_DRIVER = "com.mysql.cj.jdbc.Driver";
static final String DB_URL = "jdbc:mysql://IP:3306/DateBase?characterEncoding=utf8&useUnicode=true&useSSL=false&serverTimezone=Asia/Shanghai";
// 数据库的用户名与密码,需要根据自己的设置
static final String USER = "root";
static final String PASS = "pwd";
public static void main(String[] args) {
Connection conn = null;
Statement stmt = null;
try{
// 注册 JDBC 驱动
Class.forName(JDBC_DRIVER);
// 打开链接
System.out.println("连接数据库...");
conn = DriverManager.getConnection(DB_URL,USER,PASS);
// 执行查询
System.out.println(" 实例化Statement对象...");
stmt = conn.createStatement();
String sql;
sql = "SELECT id, userName FROM userInfo";
ResultSet rs = stmt.executeQuery(sql);
// 展开结果集数据库
while(rs.next()){
// 通过字段检索
}
// 完成后关闭
rs.close();
stmt.close();
conn.close();
}catch(SQLException se){
// 处理 JDBC 错误
se.printStackTrace();
}catch(Exception e){
// 处理 Class.forName 错误
e.printStackTrace();
}finally{
// 关闭资源
try{
if(stmt!=null) stmt.close();
}catch(SQLException se2){
}// 什么都不做
try{
if(conn!=null) conn.close();
}catch(SQLException se){
se.printStackTrace();
}
}
System.out.println("Goodbye!");
}
这是我们初学Java连接数据库时候,自己写数据库的连接和查询,可能后续我们也对上面代码进行了优化,比如我们将1,2,3,4,7这几个步骤单独拿出来进行封装,而把5,6步骤暴露出去。其实这就是模版方法模式。
这里大家看一下过程:
public class TemplateMethod {
public TemplateMethod() {
}
private void conn() {
System.out.println("连接");
}
public void exe(Object... param) {
conn();
try {
//子类中需要的业务逻辑
for (int i = 0; i < param.length; i++) {
System.out.println(param[i]);
}
} finally {
unconn();
}
}
private void unconn() {
System.out.println("释放");
}
public static void main(String[] args) {
new TemplateMethod().exe(1,2,3,4,5);
}
}
简单的说就是对不变的代码进行一次抽取,对代码的重复利用。不知道有没有小伙伴还记得定义:模版方法模式定义一个操作中的算法框架,而将一些步骤延迟到子类中,使得子类可以不改变一个算法的结构即可冲定义该算法的某些特定步骤。
我们上面好像没有涉及到子类,只是简单的抽离代码。我们来看一下Spring中的JdbcTemplate这个类
public class JdbcTemplate extends JdbcAccessor implements JdbcOperations
JdbcTemplate继承了JdbcAccessor,而JdbcAccessor就是一个抽象类,换句话说可以把它当作模版,它的方法比如getDataSource在JdbcTemplate被调用(大家可以去看一下源码)。
public abstract class JdbcAccessor implements InitializingBean {
我们继续往下看,这里我们自己定义一个抽象类出来
abstract class TemplateAccess {
public Boolean isClose() {
//默认关闭
return true;
}
private void conn() {
System.out.println("连接");
}
public abstract void exe();
private void unconn() {
if (isClose()) {
System.out.println("子类说关闭连接");
} else {
System.out.println("子类说暂时不关闭");
}
}
public void run() {
conn();
exe();
unconn();
}
}
这个抽象类中,一共有5个方法,其中exe()是抽象方法,isClose()我们通常叫它钩子函数,通过它我们能知道是否关闭数据库连接。而run方法是一次数据执行的完整过程,子类只需要重写exe()方法,如果对于是否关闭数据库有特殊要求,可以重写钩子函数。我们来写一个它的子类。
class Temp1 extends TemplateAccess {
@Override
public Boolean isClose() {
return false;
}
@Override
public void exe() {
System.out.println("执行计划1");
}
public static void main(String[] args) {
new Temp1().run();
}
}
执行结果:
Connected to the target VM, address: '127.0.0.1:50843', transport: 'socket'
连接
执行计划1
子类说暂时不关闭
Disconnected from the target VM, address: '127.0.0.1:50843', transport: 'socket'
Process finished with exit code 0
看到这里对于模版方法模式是否已经理解了?
其实模版模式很简单,也许你平时就用的很多,只是你不知道它就是一种模式
今天小程序更细题库:进入小程序
1.什么是设计模式?你是否在你的代码里面使用过任何设计模式?
2.模板模式解决了什么问题?
3.策略模式有什么好处??
4.你可以说出几个在JDK库中使用的设计模式吗?
5.举出一个例子,在这种情况你会更倾向于使用抽象类,而不是接口