简述
模版方法模式是很比较简单的一种模式,也是非常常用的一种设计模式, 相信大家工作过程中直接或间接用到过很多。
下面我们看下对应的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设计模式》