所谓模板,当然是一个通用的模型,他要把一成不变的事物提取出来,之后在其中加入个性的操作,来完成我们的需求。恰当的在程序设计中使用模板模式能够大大的缩短开发周期及代码量,这样一来,既能保证程序中各个模块的规范统一,又能减少BUG。
学习设计模式一定通过实例来驱动,spring和JDBC的整合就可以看到模板模式的身影
一般来说,使用JDBC操作数据库无非以下几个步骤
1,创建数据源并获取连接
2,通过连接创建预定义的查询
3,设定查询的参数
4,新建结果集接收查询返回的结果
而这些步骤中,1和4是每一次操作所必须的,而2和3才是开发者需要自定义的,spring抽取了这些公共的操作,把自定义操作通过接口暴露给开发者,恰当的运用了模板模式。
拿出一个spring整合JDBC中UserDao的例子,撇开整合的过程,单看jdbcTemplate,我们给jdbcTemplate传入SQL语句和指定的参数,就完成了对数据库的更新,公共的操作我们则不需要去担心
1 @Repository("userJdbcDao")
2 public class UserDao implements IUserDao {
3
4 private JdbcTemplate jdbcTemplate;
5
6 //在此注入datasource创建jdbcTemplate
7 @Resource
8 public void setDataSource(DataSource dataSource) {
9 this.jdbcTemplate = new JdbcTemplate(dataSource);
10 }
11
12 /**
13 * 更新
14 */
15 public void update(User user) {
16 jdbcTemplate.update("update t_user set name = ? where id = ?",
17 user.getName(), user.getId());
18 }
19 }
模拟spring模板的功能,通过继承的方式来实现一个模板,自定义一个模板
1 package org.duyt.template;
2
3 public abstract class JdbcTemplateByInherit {
4 /**
5 * 公共操作:开启连接
6 */
7 private void beginCon(){
8 System.out.println("开启连接");
9 }
10 /**
11 * 公共操作:关闭连接
12 */
13 private void closeCon(){
14 System.out.println("关闭连接");
15 }
16 /**
17 * 模板方法,套用公共操作,添加个性操作
18 */
19 public void execute(){
20 beginCon();
21 run();
22 closeCon();
23 }
24 /**
25 * 个性方法,暴露给继承的子类
26 */
27 public abstract void run();
28 }
29
继承类
1 package org.duyt.template.impl;
2
3 import org.duyt.template.JdbcTemplateByInherit;
4
5 public class UserDaoByIn extends JdbcTemplateByInherit{
6
7 /**
8 * 添加自定义操作
9 */
10 @Override
11 public void run() {
12 System.out.println("执行了run方法");
13 }
14
15 }
16
测试一下
1 package org.duyt.test.template;
2
3 import org.duyt.template.JdbcTemplateByInherit;
4 import org.duyt.template.impl.UserDaoByIn;
5 import org.junit.Test;
6
7 public class TestJdbcTempbyinherit {
8
9 @Test
10 public void test01(){
11 JdbcTemplateByInherit dao = new UserDaoByIn();
12 dao.execute();
13 }
14
15 }
16
结果:
开启连接
执行了run方法
关闭连接
虽然看上去很简陋,但是至少已经有了一个模板的雏形。在模板方法中,我们还可以使用“钩子函数”来控制模板方法的流程,在模板中添加钩子函数暴露给实现类,并修改模板方法
1 /**
2 * 模板方法,套用公共操作,添加个性操作
3 */
4 public void execute(){
5 beginCon();
6 if (ishookerOnOrOff()) {
7 run();
8 }
9 else{
10 System.out.println("不执行任何操作");
11 }
12
13 closeCon();
14 }
15 /**
16 * 个性方法,暴露给继承的子类
17 */
18 public abstract void run();
19
20 /**
21 * 钩子方法,可以用来控制模板方法的流程
22 * @return
23 */
24 public abstract boolean ishookerOnOrOff();
修改实现类,添加钩子方法的实现
1 @Override
2 public boolean ishookerOnOrOff() {
3 return false;
4 }
测试结果:
开启连接
不执行任何操作
关闭连接
现在回头看到jdbcTemplate,他并没有通过任何实现类去继承这个模板来调用或控制模板方法的流程,而是直接使用模板来对数据库进行操作,这样一来,就不能使用继承的方式来使用模板,要升级钩子,使用接口,使得外界能够直接使用模板方法。新建一个钩子接口
1 package org.duyt.template;
2
3 import java.util.Map;
4
5 public interface GenericDaoMethod {
6 public void invoke(String sql,Map params);
7 }
8
新建一个通过以组件形式出现的模板JdbcTemplateByComponent
1 package org.duyt.template;
2
3 import java.util.Map;
4
5 public class JdbcTemplateByComponent {
6
7 private void beginCon(){
8 System.out.println("开启连接");
9 }
10
11 private void closeCon(){
12 System.out.println("关闭连接");
13 }
14
15 public void execute(GenericDaoMethod genericDaoMethod,String sql,Map params){
16 beginCon();
17 genericDaoMethod.invoke(sql,params);
18 closeCon();
19 }
20
21 public void add(String sql,Map params){
22 execute(new GenericDaoMethod() {
23 public void invoke(String sql, Map params) {
24 System.out.println(sql);
25 System.out.println(params);
26 //使用创建的con,preparedstatement,resultset结合Sql和params执行CURD
27 }
28 }, sql, params);
29 }
30 ......其他方法略
31
32 }
33
我们看到,通过组建的方式来创建模板,需要将所有的待暴露方法都定义好在模板里,并且在每个方法中都需要实现各自的钩子方法来使用模板方法,而对于外界,也就是调用者,只需要关心传入的参数,和调取的方法能够实现的业务,无需关心连接,查询和结果集的开关等操作。基于这个思路,就基本实现了对数据库操作的模板。