前言:边动手,边动脑,才能进步,只动手不动脑,一塌糊涂
定义
又称模板方法模式,定义一个算法的骨架,并且允许子类为一个或多个步骤提供实现,属于行为性设计模式
用途
用来梳理流程标准化的业务场景
应用场景
一次性实现一个算法不变的部分,并将可变的部分留给子类去实现
Demo1
以员工从一家公司离职到另一家公司面试并上班为例(假定必须先离职才能去面试)
package com.ns.template.demo1;
/**
* 找工作类(抽象类,部分方法为protected修饰--保证子类可访问,部分方法为final修饰--保证方法不被允许修改)
*/
public abstract class FindWork {
/**
* 找工作方法,protected定义保证只有子类才能调用
*/
protected final void find(){
//1.先给当前公司提交离职申请
this.applyLeave();
//2.审批通过
this.approveLeave();
//3.拿到离职证明
this.getLeaveProve();
//4.找到下家要面试的公司
this.findCompany();
//5.人事面试
this.personalInterview();
//6.技术面试
this.technologyInterview();
//7.提交各种资料(不一定是必须的)
//在模板模式中,此类方法被称作钩子方法,用来灵活的干预流程
if(necessary()){
submitInformation();
}
//8.入职
this.doWork();
}
final void doWork() {
System.out.println("入职办理完成,开始上班了");
}
abstract void submitInformation();
protected boolean necessary() {
return false;
}
final void technologyInterview() {
System.out.println("技术面试也通过了,准备办理入职");
}
final void personalInterview() {
System.out.println("物色到一家不错的公司,人事面试通过了");
}
final void findCompany() {
System.out.println("目前成为了无业人员,开始寻找下家公司");
}
final void getLeaveProve() {
System.out.println("员工拿到离职证明");
}
final void approveLeave() {
System.out.println("公司同意该员工离职");
}
final void applyLeave(){
System.out.println("准备申请离职");
}
}
package com.ns.template.demo1;
/**
* 普通员工,不需要提交任何入职资料,不需要重写钩子方法
*/
public class GeneralPerson extends FindWork{
@Override
void submitInformation() {
}
}
package com.ns.template.demo1;
/**
* 特殊员工,需要提交入职部分资料,通过重写钩子方法
*/
public class SpecialPerson extends FindWork{
private Boolean necessary;
public SpecialPerson(Boolean necessary){
this.necessary = necessary;
}
@Override
void submitInformation() {
System.out.println("提交离职证明");
System.out.println("提交薪资流水单");
}
@Override
protected boolean necessary() {
return this.necessary;
}
}
package com.ns.template.demo1;
/**
* 测试类
*/
public class TestTemplate {
public static void main(String[] args) {
GeneralPerson generalPerson = new GeneralPerson();
generalPerson.find();
SpecialPerson specialPerson = new SpecialPerson(true);
specialPerson.find();
}
}
Demo2
以JDBC连接数据库的过程为例
package com.ns.template.demo2;
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;
/**
* JDBC连接、数据获取、释放类
*/
public abstract class JdbcTemp {
private DataSource dataSource;
public JdbcTemp(DataSource dataSource){
this.dataSource = dataSource;
}
public List<?> executeQuery(String sql, RowMapper<?> rowMapper, Object[] values){
List<?> result;
try {
//1.获取连接,从dataSource中获取
Connection coon = this.getConnection();
//2.创建语句集,通过连接对象创建执行语句
PreparedStatement pstm = this.createStatement(coon,sql);
//3.执行语句集,设置参数并执行
ResultSet rs = this.executeSql(pstm,values);
//4.处理结果集
result = this.parseResultSet(rs,rowMapper);
//5.关闭结果集
this.closeResultSet(rs);
//6.关闭语句集
this.closeStatement(pstm);
//7.关闭连接
this.closeConnection(coon);
} catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException();
}
return result;
}
private void closeConnection(Connection coon) throws SQLException {
coon.close();
}
private void closeStatement(PreparedStatement pstm) throws SQLException {
pstm.close();
}
private void closeResultSet(ResultSet rs) throws SQLException {
rs.close();
}
private List<?> parseResultSet(ResultSet rs, RowMapper<?> rowMapper) throws SQLException {
List<Object> result = new ArrayList<>();
int rowNum = 1;
while (rs.next()){
result.add(rowMapper.mapRow(rs,rowNum++));
}
return result;
}
private ResultSet executeSql(PreparedStatement pstm, Object[] values) throws SQLException {
if(values != null){
for(int i=0; i<values.length; i++){
pstm.setObject(i,values[i]);
}
}
return pstm.executeQuery();
}
private PreparedStatement createStatement(Connection coon, String sql) throws SQLException {
return coon.prepareStatement(sql);
}
private Connection getConnection() throws SQLException {
return this.dataSource.getConnection();
}
}
package com.ns.template.demo2;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
* 约束ORM逻辑的接口(实现实体之间映射关系)
* @param <T>
*/
public interface RowMapper<T> {
T mapRow(ResultSet rs, int rowNum) throws SQLException;
}
package com.ns.template.demo2;
/**
* 人员实体类
*/
public class Person {
private String userCode;
private String userName;
private String password;
private int age;
public String getUserCode() {
return userCode;
}
public void setUserCode(String userCode) {
this.userCode = userCode;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"userCode='" + userCode + '\'' +
", userName='" + userName + '\'' +
", password='" + password + '\'' +
", age=" + age +
'}';
}
}
package com.ns.template.demo2;
import javax.sql.DataSource;
import java.util.List;
/**
* 数据库操作类
*/
public class MemberDao extends JdbcTemp {
public MemberDao(DataSource dataSource) {
super(dataSource);
}
/**
* 此处可扩展,如果把查询到的字段与实体字段映射起来,而不是一个个get(小小的思考)
*/
public List<?> select(){
String sql = "select * from person";
return super.executeQuery(sql, (RowMapper<Person>) (rs, rowNum) -> {
Person person = new Person();
person.setAge(rs.getInt("age"));
person.setPassword(rs.getString("password"));
person.setUserCode(rs.getString("user_code"));
person.setUserName(rs.getString("user_name"));
return person;
},null);
}
}
package com.ns.template.demo2;
import org.apache.commons.dbcp.BasicDataSource;
/**
* 将数据源初始化封装成简单的单例模式
*/
public class DataSourceSingleton {
private static BasicDataSource dataSource;
private DataSourceSingleton(){}
static {
dataSource = new BasicDataSource();
dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://127.0.0.1:3306/redis?serverTimezone=UTC");
dataSource.setUsername("root");
dataSource.setPassword("123456");
}
public static BasicDataSource getInstance(){
return dataSource;
}
}
package com.ns.template.demo2;
import java.util.List;
/**
* 测试类
*/
public class TestJdbcTemplate {
public static void main(String[] args) {
MemberDao memberDao = new MemberDao(DataSourceSingleton.getInstance());
List<?> result = memberDao.select();
System.out.println(result);
}
}
建表语句
CREATE TABLE `person` (
`user_code` varchar(10) DEFAULT NULL COMMENT '用户代码',
`user_name` varchar(20) DEFAULT NULL COMMENT '用户名称',
`password` varchar(20) DEFAULT NULL COMMENT '密码',
`age` int(2) DEFAULT NULL COMMENT '年龄'
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='人员表';
INSERT INTO `person` VALUES ('1', '测试用户1', '123456', '1000');
总结
优点:
1.将相同处理逻辑放到父类,提高了代码的复用性
2.将不同的代码放到子类中处理,提高了代码的可扩展性
缺点:
1.类数目的增加,每个子类都要去继承父类,导致类文件数量的增多
2.父类如果添加新的抽象方法,子类都要跟着修改
最后,希望大家都能学以致用!!!