java 代码
- 在这里我首先以一个比较简单的小例子让不知道模板模式的人先有个入门的概念。(如果要想深入了解,去看<java与模式>)
- 在后面的例子我将以一个比较实用的例子来说明这种模式给我们带来的好处,并且这个例子很实用。下面我会把所有的代码
- 都贴出来,你可以直接Copy代码就可以运行,如果你已经有啦一定了解,那么就直接看第二个吧。
- 在这里我希望你把它看完,并把它理解。因为开始我在看Spring的源码的时候也是看啦好多次才把思路理清楚的。
- 首先先说说这两个例子的作用,要不然看啦大半天都不知道是什么东西。
- 第一个: 当我们去买东西的时候,东西都会打折,然而每种东西的折扣都不一样。如买Book的时候,书的折扣是 0.8 折
- 而当我们去买 Video 的时候,它是 0.7 折,如果这些分类的商品很多的时候。而我们每次都要 在每一个类
- 中写一个打折后得到的实际价格的话,那是不是感觉到很累赘。也很不爽。所以我们有必要把它抽象出来。那么
- 每个类只要从这个类继承就可以啦。如果重用的方法多的话,那么这就会带来很大的好处.
- 看源代码:
- /*
- * 这是一个模板方法的抽象类,所有的将要打折的商品都要从它继承
- * 那么就会得到getRealPrice()这个模板方法,当然,这里只是为了
- * 说明模板方法的用处
- */
- package com.dongguoh;
- public abstract class Item {
- protected abstract float getUnitPrice();
- protected abstract float getDiscountRate();
- public float getRealPrice(){
- return this.getDiscountRate()*this.getUnitPrice();
- }
- }
- package com.dongguoh;
- public class Video extends Item{
- /*
- * 在实际当中,这些要返回的值应当是从数据库当中去取
- */
- protected float getDiscountRate() {
- return 0.8f;
- }
- protected float getUnitPrice() {
- return 300;
- }
- }
- package com.dongguoh;
- public class Book extends Item {
- /*
- * 在实际当中,这些要返回的值应当是从数据库当中去取
- */
- public float getDiscountRate() {
- return 0.7f;
- }
- public float getUnitPrice() {
- return 88;
- }
- }
- 下面这是测试方法
- package com.dongguoh;
- import java.sql.*;
- import junit.framework.TestCase;
- public class TestTemplate extends TestCase {
- public void testMethod(){
- Book bk=new Book();
- Video vd=new Video();
- System.out.println("BookRealPrice: "+bk.getRealPrice());
- System.out.println("VideoRealPrice: " +vd.getRealPrice());
- }
- }
- 结果:
- BookRealPrice: 61.6
- VideoRealPrice: 240.0
- 上面这个例子比较简单,我就不多说啦,下面的是个实用的例子
- 例子二: 如果不是用Orm工具而是用经常用jdbc操作数据库的人会感到每次要连接到数据库,CRUD 数据的时候写一大串的
- try{}catch{},几乎每次都写,真是他妈的烦死啦。大家肯定有同感吧,反正我开始还不会用ORM工具的时候就觉得很麻烦的
- 而当你看啦下面这个例子后就就会觉得方便多啦.也不用写那么多的try catch{}啦,
- 直得高兴的是Spring中对这做啦很好的封装,所以我就横批写啦一个,这样就不与Spring偶合在
- 一起啦,可以单独的拿出来使用.
- 这时是数据库的表:
- 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=gb2312;
- 1.首先我们先做一个接口,现在先不管它,等下你就知道他有什么用啦
- package com.dongguoh;
- import java.sql.*;
- /*
- * 用匿名类的方式去运用这个接口
- */
- public interface IStatementCallback {
- public Object doInStatement(Statement stmt) throws RuntimeException,SQLException;
- }
- 2.而这里是最关键的,就是建一个Jdbc的模板方法,把那些经常要做的try{} catch{}都写在一个类里
- 免得以后每次都还去写。这就成啦代码复用.
- package com.dongguoh;
- import java.sql.*;
- /*
- * 在这里我就不用Spring的注入啦,直接写个完整的
- * 如果不会Spring的,也同样的像使用Spring中的JdbcTemplate类一样的使用.
- * 如果你看过Spring的书,那么这个例子也是一个Spring的入门jdbc的好例子
- *
- * 而在这里我们的这个JdbcTemplate就成啦一个通用的方法,以后我们要SQL语句连接数据库的
- * 时候不用每次都去写try{}catch{}啦,老那样写真的很烦,一次性就把它搞定啦
- */
- public class JdbcTemplate {
- public Object execute(IStatementCallback action) {
- Connection conn = null;
- Statement stmt = null;
- Object result = null;
- try {
- conn=this.getConnection();
- conn.setAutoCommit(false);
- stmt=conn.createStatement();
- //注意这一句
- result=action.doInStatement(stmt);
- conn.commit();
- conn.setAutoCommit(true);
- } catch (SQLException e) {
- transactionRollback(conn);//进行事务回滚
- e.printStackTrace();
- throw new RuntimeException(e);
- }finally{
- this.closeStatement(stmt);
- this.closeConnection(conn);
- }
- return result;
- }
- /*
- * 当发生异常时进行事务回滚
- */
- private void transactionRollback(Connection conn){
- if(conn!=null){
- try {
- conn.rollback();
- } catch (SQLException e) {
- // TODO Auto-generated catch block
- 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();
- }
- }
- }
- //取得一个Connction
- private Connection getConnection() {
- String driver = "com.mysql.jdbc.Driver";
- String url = "jdbc:mysql://127.0.0.1/Hibernate";
- Connection conn=null;
- try {
- Class.forName(driver);
- conn = DriverManager.getConnection(url, "root", "dongguoh");
- } catch (ClassNotFoundException e) {
- e.printStackTrace();
- } catch (SQLException e) {
- e.printStackTrace();
- }
- return conn;
- }
- }
- 下面是我们的测试方法:
- package com.dongguoh;
- import java.sql.*;
- import junit.framework.TestCase;
- public class TestTemplate extends TestCase {
- public void testJdbcTemplate(){
- JdbcTemplate jt=new JdbcTemplate();
- /*
- * 因为IStatementCallback是一个接口,所以我们在这里直接用一个匿名类来实现
- * 如果已经正确的插入啦一条数据的话 ,它会正确的返回一个 整数 1
- * 而我们这里的stmt是从JdbcTemplate中传过来的
- */
- int count=(Integer)jt.execute(new IStatementCallback(){
- public Object doInStatement(Statement stmt) throws RuntimeException, SQLException {
- String sql="INSERT INTO person VALUES(1,'dongguoh','123456')";
- int result=stmt.executeUpdate(sql);
- return new Integer(result);
- }
- });
- System.out.println("Count: "+count);
- /*
- * 在这里我们就把刚刚插入的数据取出一个数据,直接输出来
- *
- */
- jt.execute(new IStatementCallback(){
- public Object doInStatement(Statement stmt) throws RuntimeException, SQLException {
- String sql="SELECT name,password FROM person WHERE id=1";
- ResultSet rs=null;
- rs=stmt.executeQuery(sql);
- if(rs.next()){
- System.out.println(rs.getString("name"));
- System.out.println(rs.getString("password"));
- }
- /*
- * 在这里就直接返回一个1啦,如果你愿意的话,你可以再写一个Person类
- * 在if语句中实例化它,赋值再把它返回
- */
- return new Integer(1);
- }
- });
- }
- }
- 测试结果:
- Count: 1
- dongguoh
- 123456
- 如果你要用 PreparedStatement 的话,想传参数的话,再写一个接口来实现,再在JdbcTemplate重载一个方法
- 如public Object execute(IPreparedStatementCallback action,,Object[] objArray)再多传一个你要传递的参数数组,
- 这样做就OK啦,试试吧,感觉会更好,这就是模板方法给我们带来的好处,没事看看 设计模式 类的书感觉蛮爽的