模板方法模式介绍
它定义了一个操作中的算法骨架,将某些步骤延迟到子类中实现。
这样新的子类可以在不改变一个算法结构的前提下重新定义该算法的某些特定步骤。
例如:
-
我们去外面吃饭,一般来说有三个固定的流程
1.点菜
2.吃东西
3.买单
其中吃什么东西要看我们具体点的是什么决定,比如香干炒肉,或者宫保鸡丁。。。。
但是流程上的点菜,和买单却是必须执行的流程 -
我们去银行办理对应的业务
1.取号排队
2.办理具体的业务(现金/转账/企业/个人/理财)
3.给工作人员打分
其中具体的业务是不确定的,但是取号排队和打分却是必定要执行的步骤,所以这时候就引出了模板方法模式
当我们处理某个流程的代码都具备,但是其中某个节点的代码暂时不能确定。因此我们采用了模板方法模式,将这个节点的代码转义给子类完成。即 :处理步骤父类中定义好,具体实现延迟到子类中定义。
实战
银行案例
创建抽象类BankTemplateMethod
public abstract class BankTemplateMethod {
public void takeNumber() {
System.out.println("取号排队");
}
// 办理具体的业务(钩子方法)
public abstract void transact();
public void evaluate() {
System.out.println("反馈评分");
}
public final void process() { // 模板方法!!!
this.takeNumber();
this.transact();
this.evaluate();
}
}
创建Client
public class Client {
public static void main(String[] args) {
BankTemplateMethod btm = new DrawMoney();
btm.process();
//采用匿名内部类
BankTemplateMethod btm2=new BankTemplateMethod() {
@Override
public void transact() {
System.out.println("我要存钱");
}
};
btm2.process();
}
}
class DrawMoney extends BankTemplateMethod {
@Override
public void transact() {
System.out.println("我要取钱!!");
}
}
测试一:结果
JDBC操作数据库
使用JDBC操作数据库需要的步骤:
- 获取链接 (不可变)
- 通过连接拿到PreparedStatement对象(不可变)
- 执行SQL的增删改查 (可变)
- 处理异常(不可变)
- 关闭连接(不可变)
如果经常的数据库进行操作,那么就要写很多这种模板式的代码,很繁琐,所以我们可以使用模板方法模式解决这个问题。
模板方法抽象类
package dao;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Connection;
public abstract class JdbcTemplate02 {
//初始化参数
private Connection conn;
protected PreparedStatement ps;
protected ResultSet rs;
//定义模板方法
public final void dbOperation(String sql, Object entity) throws Exception {
getStatement(sql);//传入SQL语句,获得连接对象
crud(entity);//执行SQL的具体操作
releaseResources();//关闭连接释放资源
}
protected void getStatement(String sql) throws Exception {
String url = "jdbc:mysql://localhost:3307/demo2?user=root&password=root&useUnicode=true&characterEncoding=UTF8";
Class.forName("com.mysql.jdbc.Driver");
System.out.println("成功加载MySQL驱动程序");
conn = DriverManager.getConnection(url);
this.ps = conn.prepareStatement(sql);
}
protected abstract void crud(Object entity) throws SQLException;
private void releaseResources() throws SQLException {
if (rs != null)
rs.close();
if (ps != null)
ps.close();
if (conn != null)
conn.close();
}
}
模板的方法是dbOperation,执行顺序如下
- .获取数据库连接
- 获取PreparedStatement
- CRUD(create 添加数据read读取数据 update 修改数据delete删除数据)
- . 释放资源释放资源
接下来就是对数据库的具体操作,这里就举一个增的案例
首先:在dao包下面添加了一个User类
package dao;
public class User {
private int id;
private String name;
private int age;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public User() {
}
public User(int id, String name, int age) {
super();
this.id = id;
this.name = name;
this.age = age;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
然后创建类JdbcCreateEntity,在这里我们可以添加各种对数据库的操作,下面举例添加用户
package dao;
import java.sql.SQLException;
public class JdbcCreateEntity extends JdbcTemplate02 {
@Override
protected void crud(Object entity) throws SQLException {
User user = (User) entity;
ps.setInt(1, user.getId());
ps.setString(2, user.getName());
ps.setInt(3, user.getAge());
ps.execute();
}
}
最后再来看我们dao的实现方法,非常简洁。当然同时也添加了一个main方法测试
package dao;
public class dao {
private void addUSer(User user) throws Exception {
JdbcCreateEntity createEntity=new JdbcCreateEntity();
final String SQL = "insert into person (id,name,age) values (?,?,?)";
createEntity.dbOperation(SQL, user);
}
public static void main(String[] args) throws Exception {
User user=new User(3,"wangwu",20);
dao dao=new dao();
dao.addUSer(user);
System.out.println("添加成功");
}
}
到这里是不是又感觉打开了一扇新世界的大门,其实不需要重复发明轮子,因为考虑到使用JDBC方式访问数据库造成的重复代码的问题,Spring早就做好了现成的工具JdbcTemplate, 我们只需要使用这个工具就好了。
总结
实现一个算法时,整体步骤固定。但是某些部分易变,易变的部分可以抽象出来,供子类实现。 这个时候就可以使用模板设计模式在我们周围不乏有这样的案例
- 数据库访问的封装
- Junit单元测试
- Servlet中关于doGet/doPost方法的调用
- spring中的jdbcTemplate等