设计模式第一讲-模版方法模式

2019-07-15 18:11:57 浏览数 (1)

简述

模版方法模式是很比较简单的一种模式,也是非常常用的一种设计模式, 相信大家工作过程中直接或间接用到过很多。

下面我们看下对应的UML图和相应的代码

图例

代码

现在我们臆想一个业务场景,比如对接不同的支付渠道(大部分都是基于官方提供的sdk集成),假设我们步骤如下:

代码语言:javascript复制
1. 签名鉴权
2. 统一下单
3. 返回支付信息

对接支付宝支付的代码:

代码语言:javascript复制
package design.pattern;

public class AliPay {

    /**
     * start
     */
    public void start() {
        System.out.println("某种操作,我现在只是一个范例");

    }

    /**
     * 接口鉴权
     */
    public void auth() {
        System.out.println("支付宝--生成sign校验是否合法");
    }

    /**
     * 向第三方下订单
     */
    public void thirdOrder() {
        System.out.println("支付宝--下订单接口");
    }

    /**
     * 获取支付平台信息
     */
    public void getPayInfo() {
        System.out.println("支付宝--获取支付平台信息");
    }

}

对接微信支付的代码

代码语言:javascript复制
package design.pattern;

public class WxPay {

    /**
     * start
     */
    public void start() {
        System.out.println("某种操作,我现在只是一个范例");

    }

    /**
     * 接口鉴权
     */
    public void auth() {
        System.out.println("微信支付--生成sign校验是否合法");
    }

    /**
     * 向第三方下订单
     */
    public void thirdOrder() {
        System.out.println("微信支付--下订单接口");
    }

    /**
     * 获取支付平台信息
     */
    public void getPayInfo() {
        System.out.println("微信支付--获取支付平台信息");
    }
}

客户端调用:

代码语言:javascript复制
//支付宝支付
AliPay aliPay = new AliPay();
aliPay.start();
aliPay.auth();
aliPay.thirdOrder();
aliPay.getPayInfo();

//微信支付
WxPay wxPay = new WxPay();
wxPay.start();
wxPay.auth();
wxPay.thirdOrder();
wxPay.getPayInfo();

通过上面的例子我们发现了这两个类的代码其实有很多相似的地方,他们之间存在着重复性代码,如start方法。是先鉴权还是先下订单,这种完全依靠业务方的调用顺序。

我们用模版方法模式来优化下.

首先我们想到,先把一部分公用方法的供不同支付平台共享,把调用顺序的细节封装起来。

公共基础类(算法类):

代码语言:javascript复制
package design.pattern;

public abstract class Pay {

    /**
     * start
     */
    public void start() {
        System.out.println("某种操作,我现在只是一个范例");

    }

    abstract void auth();

    abstract void thirdOrder();

    abstract void getPayInfo();

    //实现调度顺序
    public void templateMethod() {
        //step1
        start();
        //step2
        auth();
        //step3
        thirdOrder();
        //step4
        getPayInfo();
    }
}

对应的具体支付类:

代码语言:javascript复制
package design.pattern;

public class AliPay extends Pay {

    /**
     * 接口鉴权
     */
    public void auth() {
        System.out.println("支付宝--生成sign校验是否合法");
    }

    /**
     * 向第三方下订单
     */
    public void thirdOrder() {
        System.out.println("支付宝--下订单接口");
    }

    /**
     * 获取支付平台信息
     */
    public void getPayInfo() {
        System.out.println("支付宝--获取支付平台信息");
    }

}

业务方调用者:

代码语言:javascript复制
AliPay aliPay = new AliPay();
aliPay.templateMethod();

WxPay wxPay = new WxPay();
wxPay.templateMethod();

output:

代码语言:javascript复制
某种操作,我现在只是一个范例
支付宝--生成sign校验是否合法
支付宝--下订单接口
支付宝--获取支付平台信息

某种操作,我现在只是一个范例
微信支付--生成sign校验是否合法
微信支付--下订单接口
微信支付--获取支付平台信息

经过简单的改造,pay基础类只需要关注公共部分和调用顺序就可以了,更加方便修改。而其余的业务细节由子类来实现。

但是可能还有其他的情况,比如我想对某个流程做一些开关怎么办,那就需要用到了Hook.

支付基础类

代码语言:javascript复制
package design.pattern;

public abstract class Pay {

    /**
     * start
     */
    public void start() {
        System.out.println("某种操作,我现在只是一个范例");

    }

    abstract void auth();

    abstract void thirdOrder();

    abstract void getPayInfo();

    public void templateMethod() {
        //step1
        start();
        //step2
        auth();
        //step3
        if (isOrderOpen()) {
            thirdOrder();
        }
        //step4
        getPayInfo();
    }

    /**
     * 是否开启订单方式
     *
     * @return
     */
    protected boolean isOrderOpen() {
        return true;
    }
}

默认是开启向第三方下订单的,比如某个平台不需要这个操作,就可以覆盖isOrderOpen方法就可以了。

代码语言:javascript复制
package design.pattern;

public class AliPay extends Pay {

    /**
     * 接口鉴权
     */
    public void auth() {
        System.out.println("支付宝--生成sign校验是否合法");
    }

    /**
     * 向第三方下订单
     */
    public void thirdOrder() {
        System.out.println("支付宝--下订单接口");
    }

    /**
     * 获取支付平台信息
     */
    public void getPayInfo() {
        System.out.println("支付宝--获取支付平台信息");
    }

    protected boolean isOrderOpen() {
        //todo
        return false;
    }
}

衍生出来的好莱坞原则:

别调用(打电话给)我们,我们会调用(打电话给)你

这句话很霸道。。。

其实意思高层组件允许低层组件挂钩到系统上,但是高层组件决定什么和如何去使用这些低层组件.换句话说: 高层组件对待低层组件的方式就是“别调用我们,我们会调用你”。

总结: 上面提出的例子不一定适合这个模式,希望能够理解模版方法模式的意思就好了。 简要来说: 模版方法模式是通过把不变行为搬到了超类,去除了子类中的重复代码。

相似模式: 策略模式

参考资料: 《大话设计模式》、《Head First设计模式》

0 人点赞