一、概述
使用一个抽象类将部分的逻辑以具体的方法以及具体的构造子实现,然后声明一些抽象方法来迫使子类实现剩余的逻辑,不同的子类对剩余的逻辑有不同的实现。
优点
利用模板模式将相同处理逻辑的代码抽取到抽象类中,可以提搞代码发重性
将不同的代码放置在不同的子类中,通过对子类的扩展添加新的行为,提搞代码的扩展性
把不变的行为写在父类上,去除子类的重复代码,提供了很好的代码的复用平台,符合开闭原则
缺点
- 类数目的增加,每个抽象类都要有子类来实现
- 因为类数目的增加,也间接地导致系统实现的复杂度
- 继承自身的缺陷,如果抽象类新增了一个方法,所有的子类都要实现一遍
应用场景
- 一次性实现算法的不变的部分,并将可变的行为留给了子类来实现
- 各子类中公共的行为被提取出来并集中到一个公共的父类之中,从而避免了代码的重复
二、模板方法模式结构
类图
结构说明
角色 | 说明 |
---|---|
抽象模板角色(Abstract Template) | 定义一个或多个抽象操作(基本操作),以便让子类实现,给出了一个顶级逻辑的骨架,并实现了一个模板方法(具体方法),顶级逻辑也有可能调用一些具体方法 |
具体模板角色(Concrete Template) | 实现父类定义的一个或多个抽象方法,它们是一个顶级逻辑的组成步骤,每一个抽象模板角色都可以有任意多个具体模板角色与之对应,而每个具体模板角色都可以给出这些抽象方法(也就是顶级逻辑的组成步骤)的不同实现,从而使得顶级逻辑的实现各不相同 |
三、案例演示
抽象模板角色类
package com.deepexi.pattern.template;
/**
* @Author: CaoJun
* @Description: 抽象模板角色:(Abstract Template)
* @Create: 2020-01-21 13:22
**/
public abstract class AbstractTemplate {
/**
* 模板方法,顶级逻辑,把基本操作方法组合在一起形成一个总算法或者总行为的方法
*/
public void templateMethod() {
abstractMethod();
doHookMethod();
concreteMethod();
}
protected abstract void abstractMethod();
/**
* 钩子方法(可以置换掉)
*/
protected void doHookMethod() {
System.out.println();
}
/**
* 具体的方法(不可以被置换掉)
*/
private void concreteMethod() {
System.out.println("业务相关代码实现");
}
}
具体模板角色类
package com.deepexi.pattern.template;
/**
* @Author: CaoJun
* @Description: 具体模板角色:(Concrete Template) 可以有多个
* @Create: 2020-01-21 13:24
**/
public class ConcreteTemplate extends AbstractTemplate {
@Override
protected void abstractMethod() {
System.out.println("抽象方法的实现");
}
/**
* 钩子方法:替换父类可变的部分,但是子类不可以改变模板方法所代表的顶级逻辑
*/
@Override
protected void doHookMethod() {
System.out.println("钩子方法:替换父类可变的部分");
}
}
客户端测试
package com.deepexi.pattern.template;
/**
* @Author: CaoJun
* @Description: 客户端测试
* @Create: 2020-01-21 13:28
**/
public class Client {
public static void main(String[] args) {
AbstractTemplate template = new ConcreteTemplate();
template.templateMethod();
}
}
业务场景案例
约束 ORM 逻辑的接口
package com.deepexi.pattern.template.demo;
import java.sql.ResultSet;
/**
* @Author: CaoJun
* @Description: 约束 ORM 逻辑的接口
* @Create: 2020-01-21 14:36
**/
public interface RowMapper<T> {
T mapRow(ResultSet rs, int rowNum) throws Exception;
}
封装了所有处理流程的抽象类
package com.deepexi.pattern.template.demo;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
/**
* @Author: CaoJun
* @Description: 封装了所有处理流程的抽象类
* @Create: 2020-01-21 14:37
**/
public abstract class JdbcTemplate {
private DataSource dataSource;
public JdbcTemplate(DataSource dataSource) {
this.dataSource = dataSource;
}
public List<?> excuteQuery(String sql, RowMapper<?> rowMapper, Object[] values) {
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet rs = null;
try {
// 1、获取连接
connection = this.createConnection();
// 2、创建语句集
preparedStatement = this.createPreparedStatement(connection, sql);
// 3、执行语句集
rs = this.excuteQuery(preparedStatement, values);
// 4、处理结果集并返回
return this.handleResultSet(rs, rowMapper);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
// 5、关闭结果集
if (rs != null)
this.closeResultSet(rs);
// 6、关闭语句集
if (preparedStatement != null)
this.closePreparedStatement(preparedStatement);
// 7、关闭连接
if (connection != null)
this.closeConnection(connection);
} catch (SQLException e) {
e.printStackTrace();
}
}
return null;
}
private Connection createConnection() throws SQLException {
return dataSource.getConnection();
}
private PreparedStatement createPreparedStatement(Connection connection, String sql) throws SQLException {
return connection.prepareStatement(sql);
}
private ResultSet excuteQuery(PreparedStatement preparedStatement, Object[] values) throws SQLException {
for (int i = 0; i < values.length; i++) {
preparedStatement.setObject(i, values[i]);
}
return preparedStatement.executeQuery();
}
private List<?> handleResultSet(ResultSet rs, RowMapper<?> rowMapper) throws Exception {
List<Object> result = new ArrayList<>();
int rowNum = 1;
while (rs.next()) {
result.add(rowMapper.mapRow(rs, ++rowNum));
}
return result;
}
private void closeResultSet(ResultSet rs) throws SQLException {
rs.close();
}
private void closePreparedStatement(PreparedStatement preparedStatement) throws SQLException {
preparedStatement.close();
}
private void closeConnection(Connection connection) throws SQLException {
connection.close();
}
}
模拟模型对象
package com.deepexi.pattern.template.demo;
import lombok.Data;
import java.util.Date;
/**
* @Author: CaoJun
* @Description:
* @Create: 2020-01-21 14:50
**/
@Data
public class Person {
private String name;
private int sex;
private String character;
private Date birthday;
}
模式数据访问层
package com.deepexi.pattern.template.demo;
import javax.sql.DataSource;
import java.util.List;
/**
* @Author: CaoJun
* @Description: Person 数据访问层
* @Create: 2020-01-21 14:51
**/
public class PersonDao extends JdbcTemplate {
public PersonDao(DataSource dataSource) {
super(dataSource);
}
public List<Person> selectAll() {
String sql = "SELECT * FROM tb_person;";
return (List<Person>) super.excuteQuery(sql, (RowMapper<Person>) (rs, rowNum) -> {
Person person = new Person();
person.setName(rs.getString("name"));
person.setBirthday(rs.getDate("date"));
person.setCharacter(rs.getString("character"));
person.setSex(rs.getInt("sex"));
return person;
}, null);
}
}
测试
package com.deepexi.pattern.template.demo;
import java.util.List;
/**
* @Author: CaoJun
* @Description: 客户端测试
* @Create: 2020-01-21 15:05
**/
public class ClientTest {
public static void main(String[] args) {
// 会出现空指针,使用时候可以注入个 DataSource
PersonDao personDao = new PersonDao(null);
List<Person> personList = personDao.selectAll();
System.out.println(personList);
}
}