每日一学设计模式-模板方法

一、概念

在方法中定义算法的骨架,同时将一些步骤的实现推迟到子类。模板方法允许子类重新定义算法的某些步骤,而无需更改算法的结构。

二、解释

真实世界理解:

人的一生都要经过幼年、少年、老年(具体方法),但每个人的一生又各不相同(抽象方法),虽然青年时期都要工作,但你可以选择对工作的态度(钩子方法)。

模板方法中三类角色:

  1. 具体方法(Concrete Method):算法骨架,不想被修改应使用final修饰
  2. 抽象方法(Abstract Method):子类必须重写的方法
  3. 钩子方法(Hook Method):有默认实现的方法,子类可以选择性重写

三、实例

创建一个人生算法骨架。

public static abstract class Life {

    //具体方法
    public final void life() {
        //幼年
        childhood();
        //青年
        youth();
        //老年
        old();
    }

    //抽象方法
    public abstract void childhood();

    private void youth() {
        System.out.println(selectAttitude() + "地生活");
    }

    //抽象方法
    public abstract void old();

    //钩子方法
    public String selectAttitude() {
        return "";
    }

}

程序员的一生

public static class Pogrammer extends Life {
    @Override
    public void childhood() {
        System.out.println("调皮捣蛋");
    }
    @Override
    public String selectAttitude() {
        return "忙碌";
    }
    @Override
    public void old() {
        System.out.println("住进ICU");
    }
}

老师的一生

public static class Teacher extends Life {
    @Override
    public void childhood() {
        System.out.println("好好读书");
    }
    @Override
    public String selectAttitude() {
        return "辛勤";
    }
    @Override
    public void old() {
        System.out.println("钓鱼喝茶");
    }
}

执行

public static void main(String[] args) {
    //程序员的一生
    Life pogrammer = new Pogrammer();
    pogrammer.life();
    //老师的一生
    Life teacher = new Teacher();
    teacher.life();
}

四、适用性

  • 实现一次算法的不变部分,将可能变化的行为留给子类
  • 当子类拥有共同行为时,应该在一个共同类中抽离公用和抽象差异,以避免代码重复
  • 控制子类扩展。可以在特定地点设置“钩子方法”,只允许对“钩子方法”进行重写扩展

五、应用

5.1 JdbcTemplate

JdbcTemplate.update.StatementCallback.doInStatment和getSql就是一个抽象方法,留给子类扩展。

public int update(final String sql) throws DataAccessException {
    Assert.notNull(sql, "SQL must not be null");
    if (logger.isDebugEnabled()) {
        logger.debug("Executing SQL update [" + sql + "]");
    }

    /**
     * Callback to execute the update statement.
     */
    class UpdateStatementCallback implements StatementCallback<Integer>, SqlProvider {
        @Override
        public Integer doInStatement(Statement stmt) throws SQLException {
            int rows = stmt.executeUpdate(sql);
            if (logger.isTraceEnabled()) {
                logger.trace("SQL update affected " + rows + " rows");
            }
            return rows;
        }
        @Override
        public String getSql() {
            return sql;
        }
    }

    return updateCount(execute(new UpdateStatementCallback()));
}

execute就是具体方法/抽象方法,它定义了相同的步骤,包括打开链接、创建Statement、关闭连接,以此组成算法骨架。

public <T> T execute(StatementCallback<T> action) throws DataAccessException {
    Assert.notNull(action, "Callback object must not be null");

    Connection con = DataSourceUtils.getConnection(obtainDataSource());
    Statement stmt = null;
    try {
        stmt = con.createStatement();
        applyStatementSettings(stmt);
        T result = action.doInStatement(stmt);
        handleWarnings(stmt);
        return result;
    }
    catch (SQLException ex) {
        // Release Connection early, to avoid potential connection pool deadlock
        // in the case when the exception translator hasn't been initialized yet.
        String sql = getSql(action);
        JdbcUtils.closeStatement(stmt);
        stmt = null;
        DataSourceUtils.releaseConnection(con, getDataSource());
        con = null;
        throw translateException("StatementCallback", sql, ex);
    }
    finally {
        JdbcUtils.closeStatement(stmt);
        DataSourceUtils.releaseConnection(con, getDataSource());
    }
}

5.2 AbstractList

JDK 中 java.util.AbstractList抽象集合类,add作为抽象方法留给子类扩展,addAll作为具体方法为骨架。同时addAll也是抽象方法,也可以给子类扩展。

public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> {
    
    //新增元素的方法,留给子类实现
    public void add(int index, E element) {
        throw new UnsupportedOperationException();
    }
    
    //模板方法。新增目标集合类的所有元素,默认调用 add 方法实现,也可以被子类重写
    public boolean addAll(int index, Collection<? extends E> c) {
        rangeCheckForAdd(index);
        boolean modified = false;
        for (E e : c) {
            add(index++, e);
            modified = true;
        }
        return modified;
    }
    
}

六、参考

菜鸟教程-模板方法

Github设计模式实现

大话设计模式

Github设计模式

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值