fred-ye / summary

my blog
43 stars 9 forks source link

[Design-Pattern]-TemplateMethod #3

Open fred-ye opened 10 years ago

fred-ye commented 10 years ago

模板方法:模板方法是在一个方法中定义一个算法的骨架,这个骨架中中可能会有多个算法,将骨架中部分算法的实现交给子类,模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤(很多时候用hook来实现,后面会讲到)。
示例: 一个简单的例子,泡茶和泡咖啡的操作都是一样的(1)烧水 (2)加原料tea/coffee (3)根据需要是否加糖。[就这么多,不搞复杂]由于操作流程一样,刚三步操作就是一个模板。将以上三个步骤抽取到一个方法中,此方法便是模板方法。将模板方法所在的类定义为抽象类。

abstract class TemplatePatternClass {
    final void prepare() { //这便是一个模板方法,定义成final,不让子类覆盖
        boilWater();
        addIngredient();
        if(needSugar()) {
            addSugar();
        }
    }
    public void boilWater() {
        System.out.println("------boil water ----");
    }
    public void addSugar() {
        System.out.println("------add Sugar ----");
    }
    abstract void addIngredient();//此方法的实现由子类完成。
    boolean needSugar() { //needSugar是一个hook方法,子类可以通过override它来修改模板方法的逻辑
        return false;
    }
}
public class Coffee extends TemplatePatternClass {

    @Override
    void addIngredient() {
       System.out.println("----------add coffee--------");
    }

    @Override
    boolean needSugar(){
        return true;
    }
}
public class Tea extends TemplatePatternClass {

    @Override
    void addIngredient() {
        System.out.println("----------add tea-----------");
    }
    @Override
    boolean needSugar(){ //Tea中不需要加糖,所以此处override needSugar这个hook方法,这将改变模板方法中的部分逻辑
        return false;
    }
}
public class TestTemplatePattern {
    public static void main(String args[]) {
        Tea tea = new Tea();
        tea.prepare();
        System.out.println("****************************************");
        Coffee coffee = new Coffee();
        coffee.prepare();
    }
}
------boil water ----
----------add tea-----------
****************************************
------boil water ----
----------add coffee--------
------add Sugar ----

模板方法在jdbc操作中的使用

通常我们操作jdbc 从数据库中取数据,代码会这样写

public List<User> getUserByDept(int deptId) {
    Connection conn = null;
    PreparedStatement stmt = null;
    ResultSet rs = null;
    String sql = "SELECT id, name, dept_id FROM user WHERE dept_id = ? "; 
    List<User> userList = new ArrayList<User>();
    try {
        conn = JDBCUtil.getConnection(); //JDBCUtil是自己写的一个工具类用来连db和释放资源
        stmt = conn.prepareStatement(sql);
        stmt.setInt(1, deptId);
        rs = stmt.executeQuery();
        while (rs.next()) {
            User user = new User();
            user.setId(rs.getInt("id"));
            user.setName(rs.getString("name"));
            user.setDeptId(rs.getInt("dept_id"));
            userList.add(user);
        }
    } catch(SQLException e) {
        //Log to file.
    } finally {
        JDBCUtil.release(rs, stmt, conn);
    }
    return userList;
}

以上代码是根据某一个条件查询User,如果接着有一个需求,需要去根据出版社查Book, 我们的代码写法肯定也一样,都是

于是写出了如下代码: 回调接口

public interface JDBCCallBack<T> {
        //将结果集转成对象
    public T rsToObject(ResultSet rs) throws SQLException;
       //设置查询参数
    public void setParameter(PreparedStatement stmt) throws SQLException;
}

模板方法

public class JDBCTemplate<T> {
    public List<T>  query(String sql, JDBCCallBack <T>callBack) {
        Connection conn = null;
        PreparedStatement stmt = null;
        ResultSet rs = null;
        List<T> data = new ArrayList<T>();
        try {
            conn = JDBCUtil.getConnection();
            stmt = conn.prepareStatement(sql);
            callBack.setParameter(stmt);
            rs = stmt.executeQuery();
            while (rs.next()) {
                T obj =  callBack.rsToObject(rs);
                data.add(obj);
            }
        } catch(SQLException e) {
            //Log to file.
        } finally {
            JDBCUtil.release(rs, stmt, conn);
        }
        return data;
    }
}

我们把公共部分都抽取到JDBCTemplate类中的query 方法中。

于是,原来的查询User的方法便可以简写成下面这个样子

public List<User> getUserByDept(final int deptId) {
    String sql = "SELECT id, name, dept_id FROM user WHERE dept_id = ? "; 
    return new JDBCTemplate<User>().query(sql, new JDBCCallBack<User>() {
        @Override
        public User rsToObject(ResultSet rs) throws SQLException {
            User user = new User();
            user.setId(rs.getInt("id"));
            user.setName(rs.getString("name"));
            user.setDeptId(deptId);
            return user;
        }
        @Override
        public void setParameter(PreparedStatement stmt) throws SQLException{
            stmt.setInt(1, deptId);
        }           
    });
}