定义一个操作中的算法骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。也就是说:假如某些操作代码基本相同,只是其中一部分会经常改变,则可以使用模板方法,将不变的部分作为一个模板,将容易变动的部分让子类来实现。
关键代码:在抽象类实现,其他步骤在子类实现。
使用场景:
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) 新建一个实体类 Person
public class Person implements Serializable { private String id; private String name ; private String password; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } }
3)建一个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观察者模式