模板方法模式

来源:互联网 发布:如何在淘宝上找店铺 编辑:程序博客网 时间:2024/05/15 06:27

定义&示例

HeadFirst定义:在一个方法中定义了一个算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。

其实就是将一些算法、业务步骤封装到一个方法中,使用者直接调用该模板方法,这样保证该步骤不会出错,减轻调用方压力。

老规矩先放一个demo github传送门

demo我假设了我们常用的12306买火车票场景。

把下单支付环节抽象为一个模板方法。

交易抽象类,也是模板方法所在的基类

/** * 模板基类 *  * @author yasin * */public abstract class Trade {    /**     * 交易模板方法     * 1.冻结该票     * 2.进行支付     * 3.支付成功->出票     * 4.解冻     *      * @author yasin     * @param name     */    public void order(String name){        frozen(name);        if(pay()){            deliver(name);        }        unfrozen(name);    }    /**     * 冻结该票     *      * @author yasin     * @param name     */    private  void frozen(String name){        System.out.println(name+" 已经被冻结");    }    /**     * 支付,抽象方法,交由具体的实体类实现     * @author yasin     * @return     */    protected abstract boolean pay();    /**     * 解冻     *      * @author yasin     * @param name     */    private void unfrozen(String name){        System.out.println(name+" 已经被解冻");    }    /**     * 出票     * @author yasin     * @param name     */    private void deliver(String name){        System.out.println(name +" 已经出票");    } }

像冻结,解冻,出票这些实现都是固定的,就在基本中实现了。但支付环节可以使用不同的支付方式,不同的支付方式又会调用不同的sdk,执行不同的方法。
所有我将pay()方法交由Trade的子类实现。

这里设计了ZhiFuBaoPay和CardPay两个子类,其pay方法通过调用不同的api实现自己的支付环节(由于本文的侧重点不在这,就省略没写)

public class ZhiFuBaoPay extends Trade {    /**     * 其实这里也是一个模板方法     * 1.获取支付账号     * 2.扣除该账号金额     * 3.为对方加入对应金额     *      * 这里就省略了,默认实现是支付成功,返回了true     */    @Override    public boolean pay() {        System.out.println("使用了 支付宝 支付了金额");        return true;    }}

下面就是一个买家下单买票,代码中只需要选择支付方式(实例化对应的类),调用一个trade方法就能实现复杂的支付下单环节了,保证每个步骤都存在,不会因为实现的子类而漏掉一个方式,也节省了代码量。

public class Buyer {    @Test    public void main(){        //车票路段        String name = "北京到济宁";        //使用支付宝进行交易//      Trade pay = new ZhiFuBaoPay();//      pay.order(name);        //使用银行卡进行交易        Trade cardPay = new CardPay();        cardPay.order(name);    }}

这里的pay()方法还是一个钩子,通过其返回值,可以对模板方法的流程进行控制。

好莱坞原则 这里就引出了一个好莱坞原则:别调用我们,我们会调用你。

好莱坞原则是为了防止“依赖腐败”的实现发生,一个高层组件和底层组件相互依赖,高层组件依赖边层组件,边层组件又依赖底层组件,这样的依赖关系真的很乱,这就是依赖腐败问题。

当高层组件和底层组件必须依赖,那就得约定让一方只调用一方,避免相互调用。就像pay方法由底层实现,高层调用,底层不会调用高层的任何方法,保证代码的可读性。

java api的使用

模板方法是一个易于理解使用,但确实很实用的模式,java api中组数的排序也是应用这个设计思想,虽然它不是完全符合模板方法的。

java Arrays#sort方法

 public static <T> void sort(T[] a, Comparator<? super T> c) {        if (c == null) {            sort(a);        } else {            if (LegacyMergeSort.userRequested)                legacyMergeSort(a, c);            else                TimSort.sort(a, 0, a.length, c, null, 0, 0);        }    }

这里的Comparator是用于比较的,因为Arrays是想比较任何对象的,但开发者自己定义的类的比较方式是不确定的,这里就将比较方法暴露出来,交于其具体实现,
开发者只需要让其类实现Comparable接口,实现其比较大小的方法就可以对其对象数据进行排序了。具体的排序方法就是模板方法了,开发者完全不需要关心。