设计模式-15 模板模式

一 模板模式

  定义一个操作中的算法骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。也就是说:假如某些操作代码基本相同,只是其中一部分会经常改变,则可以使用模板方法,将不变的部分作为一个模板,将容易变动的部分让子类来实现。

关键代码:在抽象类实现,其他步骤在子类实现。

使用场景:

Spirng 中对 Jdbc的支持

类图 :

二 实现代码

1 例子1

1) 回调接口

ICallBack.java

public interface ICallBack {
    String doCallBack();
    String sayHello(String name);
}

2) 调用者

Invoker.java

public class Invoker {
    private ICallBack callback;

    // 调用实现类的方法
    public void setCallback(ICallBack callback) {
        this.callback = callback;
    }

    // 业务需要的时候,通过委派,来调用实现类的具体方法
    public void doCallback() {
        System.out.println(callback.doCallBack());
    }

    public void sayHello(String name){
        System.out.println(callback.sayHello(name));
    }
}

3) 测试回调函数

TemplateDemo.java

public class TemplateDemo {

    public static void main(String[] args) {
        Invoker invoker = new Invoker();
        invoker.setCallback(new ICallBack() {
            public String doCallBack() {
                return "hello, It is " + new Date();
            }

            @Override
            public String sayHello(String name) {
                return "hello " + name;
            }

        });
        invoker.doCallback();
        invoker.sayHello("wangwu");

    }

}

2 例子2 JdbcTemplate

数据库的表

DROP DATABASE IF EXISTS `hibernate`;
CREATE DATABASE `hibernate` ;
USE `hibernate`;
CREATE TABLE `person` (
  `id` int(32) NOT NULL DEFAULT ‘0‘,
  `name` varchar(20) NOT NULL,
  `password` varchar(20) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;  

1)做一个接口

IStatementCallback.java

public interface IStatementCallback {
    // 用匿名类的方式去运用这个接口
    public Object doInPreparedStatement(PreparedStatement prest, String sql, Serializable object)
            throws RuntimeException, SQLException;
}

2)建一个Jdbc的模板方法,把那些经常要做的try{} catch{}都写在一个类里,免得以后每次都还去写。这就成啦代码复用

JdbcTemplate.java

import java.io.Serializable;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Statement;

public class JdbcTemplate {
    // 取得一个Connction
    private Connection getConnection() {
        String driver = "com.mysql.jdbc.Driver";
        String url = "jdbc:mysql://127.0.0.1:3306/Hibernate";
        Connection conn = null;
        try {
            Class.forName(driver);
            conn = DriverManager.getConnection(url, "root", "123456");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return conn;
    }

    public Object execute(IStatementCallback action, String sql, Serializable object) {
        Connection conn = null;
        PreparedStatement prest = null;
        Object result = null;
        try {
            conn = this.getConnection();
            conn.setAutoCommit(false);
            prest = conn.prepareStatement(sql);
            // 注意这一句
            result = action.doInPreparedStatement(prest, sql, object);
            conn.commit();
            conn.setAutoCommit(true);
        } catch (SQLException e) {
            transactionRollback(conn);// 进行事务回滚
            e.printStackTrace();
            throw new RuntimeException(e);
        } finally {
            this.closePrepareStatement(prest);
            this.closeConnection(conn);
        }
        return result;
    }

    /*
     * 当发生异常时进行事务回滚
     */
    private void transactionRollback(Connection conn) {
        if (conn != null) {
            try {
                conn.rollback();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

    }

    // 关闭打开的PreparedStatement
    private void closePrepareStatement(PreparedStatement pstmt) {
        if (pstmt != null) {
            try {
                pstmt.close();
                pstmt = null;
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }

    // 关闭打开的Statement
    private void closeStatement(Statement stmt) {
        if (stmt != null) {
            try {
                stmt.close();
                stmt = null;
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }

    // 关闭打开的Connection
    private void closeConnection(Connection conn) {
        if (conn != null) {
            try {
                conn.close();
                conn = null;
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }

}

3)运行自定义的JdbcTemplate的测试类

TestTemplate.java

public class TestTemplate {

    public void testInsertData() {
        JdbcTemplate jt = new JdbcTemplate();
        /*
         * 因为IStatementCallback是一个接口,所以我们在这里直接用一个匿名类来实现 如果已经正确的插入的一条数据的话
         * ,它会正确的返回一个 整数 1 而这里的stmt是从JdbcTemplate中传过来的
         */
        String sql = "insert into person values(?,?,?)";
        Person person = new Person();
        Random random = new Random();
        String uuid = random.nextInt(100000000) + "";
        person.setId(uuid);
        person.setName("wangwu");
        person.setPassword("123456");
        int count = (Integer) jt.execute(new IStatementCallback() {

            public Object doInPreparedStatement(PreparedStatement prest, String sql, Serializable object)
                    throws RuntimeException, SQLException {
                Person person = (Person) object;
                person.debugPrint();
                prest.setString(1, person.getId());
                prest.setString(2, person.getName());
                prest.setString(3, person.getPassword());
                return prest.executeUpdate();
            }

        }, sql, person);
        System.out.println("Count: " + count);

    }

    public void testGetData() {
        JdbcTemplate jt = new JdbcTemplate();
        HashMap clause = new HashMap();
        clause.put("name", "wangwu");
        String sql = "select * from person where name = ?";
        List persons = (List) jt.execute(new IStatementCallback() {

            @Override
            public Object doInPreparedStatement(PreparedStatement prest, String sql, Serializable object)
                    throws RuntimeException, SQLException {
                HashMap clause = (HashMap) object;
                String nameClause = (String) clause.get("name");
                prest.setString(1, nameClause);
                ResultSet rst = prest.executeQuery();

                String id = null;
                String name = null;
                String password = null;
                Person person = null;
                List list = new ArrayList();

                while (rst.next()) {
                    id = rst.getString("id");
                    name = rst.getString("name");
                    password = rst.getString("password");
                    person = new Person();
                    person.setId(id);
                    person.setName(name);
                    person.setPassword(password);
                    list.add(person);
                }
                return list;
            }

        }, sql, clause);
        System.out.println("persons size=" + persons.size());
    }

    public static void main(String[] args) {
        TestTemplate test = new TestTemplate();
        // test.testInsertData();
        test.testGetData();
    }

}

下一篇 设计模式-16观察者模式

时间: 2024-08-10 03:57:16

设计模式-15 模板模式的相关文章

【设计模式】模板模式

引子 这是一个很简单的模式,却被非常广泛的使用. 之所以简单是因为在这个模式中仅仅使用到了继承关系. 继承关系由于自身的缺陷,被专家们扣上了“罪恶”的帽子. “使用委派关系代替继承关系”, “尽量使用接口实现而不是抽象类继承”等等专家警告,让我们大家对继承“另眼相看”. 其实,继承还是有很多自身的优点所在.只是被大家滥用的似乎缺点更加明显了. 合理的利用继承关系,还是能对你的系统设计起到很好的作用的. 而模板方法模式就是其中的一个使用范例. 定义与结构 模板方法(Template Method)

设计模式之模板模式

模板模式是一个非常简单的行为类模式. 模板方法Gof的定义是:在一个方法里定义算法的骨架,将一些步骤延迟到其子类. 模板模式包含一个抽象的类和它的实现类,我们在抽象类中定义骨架,需要用到的方法都是抽象方法,具体的实现由它的子类来完成. eg: public abstract class Template{ public void printDate(){ // 显示排序后的List sort(list); } public List sort(List list); } public class

c++设计模式15 --组合模式

今天研究了一下设计模式15 组合模式 本人是菜鸟一枚,所以一开始完全不懂组合究竟是什么意思.先上图一张,树形结构图: 文档说,如果想做出这样的结构,通常考虑组合模式.那是为什么呢?现在让我们看一下组合模式的类图一本结构 想了很久,结合源代码,才搞明白,其实这个组合,意思就是说,如果我们要做这种树状结果,比如公司想让我们吧所有部门人员的 姓名,职位,薪水遍历出来,这个时候怎么办呢?那我们看树状机构图,有叶子结点和枝干结点,2种,但是2种有共性,那就是每个结点都有姓名,职位,薪水.所有叶子结点和枝干

C#设计模式(15)——命令模式(Command Pattern)

原文:C#设计模式(15)--命令模式(Command Pattern) 一.前言 之前一直在忙于工作上的事情,关于设计模式系列一直没更新,最近项目中发现,对于设计模式的了解是必不可少的,当然对于设计模式的应用那更是重要,可以说是否懂得应用设计模式在项目中是衡量一个程序员的技术水平,因为对于一个功能的实现,高级工程师和初级工程师一样都会实现,但是区别在于它们实现功能的可扩展和可维护性,也就是代码的是否“优美”.可读.但是,要更好地应用,首先就必须了解各种设计模式和其应用场景,所以我还是希望继续完

设计模式之 - 模板模式(Template Pattern)

引入:这几天在看一本讲spring源码的书<SPRING技术内幕>里面在讲加载配置文件的时候,可以有不同的加载方式,如根据文件系统目录加载配置文件(FileSystemXmlApplicationContext),类路径加载配置文件(ClassPathXmlApplicationContext),以及根据项目上下文目录(XmlWebApplicationContext)加载配置文件.这个在加载的过程中就使用了模板设计模式,所以就来学习下模板设计模式. 1. 模板设计模式在书中定义:  定义一个

设计模式之模板模式 template

设计模式 模板模式如果有一个流程如下step1();step2();step3();step4();step5();其中step3() step5()是需要用户自己编写使用其他步骤是固定的那么可以写成 // 11111.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include <iostream> #include <memory> using namespace std; class Lib { public:

设计模式3:模板模式(1)

定义: 定义一个操作中的算法的骨架,而将一些步骤延迟到子类中. 概述: 定义一个功能时,功能的一部分是确定的,而另一部分不确定,确定的部分需要用到不确定的部分,把不确定的部分暴露出去,让子类实现. 模板模式与抽象类和抽象方法联系在一起,其大致框架如下: 1 abstract class 类名{ 2 //确定部分 3 public void f(){ 4 ... 5 f1(); 6 } 7 8 //不确定部分 9 public abstract void f1(); 10 } 示例: 1 pack

JAVA设计模式之模板模式

在阎宏博士的<JAVA与模式>一书中开头是这样描述模板方法(Template Method)模式的: 模板方法模式是类的行为模式.准备一个抽象类,将部分逻辑以具体方法以及具体构造函数的形式实现,然后声明一些抽象方法来迫使子类实现剩余的逻辑.不同的子类可以以不同的方式实现这些抽象方法,从而对剩余的逻辑有不同的实现.这就是模板方法模式的用意. 模板方法模式的结构 模板方法模式是所有模式中最为常见的几个模式之一,是基于继承的代码复用的基本技术. 模板方法模式需要开发抽象类和具体子类的设计师之间的协作

设计模式7——模板模式

模板模式特点: 提取相同的特性放在基类中,而将不同的特性作为一个借口抽象出来,放到派生类中进行具体实现. Template.h内容 1 #ifndef Template_H_H 2 #define Template_H_H 3 4 #include <iostream> 5 #include <string> 6 using namespace std; 7 8 9 class Person 10 { 11 public: 12 void display() { cout <