笔记八 模板模式(Template Pattern)
1. 模板模式—是什么
专业版
含义:定义了一个操作中的算法的骨架,而将部分步骤的实现在子类中完成。
内在含义:是基于继承的代码复用的基本技术。
生活版
例如:
- 在造房子的时候,地基、走线、水管都一样,只有在建筑的后期才有加壁橱加栅栏等差异。
- 西游记里面菩萨定好的 81 难,这就是一个顶层的逻辑骨架。
2. 模板模式—作用
3. 模板模式—核心使用规则
将这些通用算法行为抽象出来在抽象类中,其他步骤在子类实现。
AbstractClass
:抽象类,定义并实现一个模板方法。这个模板方法定义了算法的骨架,而逻辑的组成步骤在相应的抽象操作中,推迟到子类去实现 ConcreteClass
: 实现实现父类所定义的一个或多个抽象方法。
4. 模板模式—应用场景
有多个子类共有的方法,且逻辑相同;重要的、复杂的方法,可以考虑作为模板方法。
5. 模板模式—案例 1:聚合支付平台-回调
聚合支付平台-异步回调-使用模板模式-结构图,如下:

1. 定义共同算法骨架
- 创建抽象类 :
AbstractPayCallbackTemplate.java
- 共同算法骨架:
asyncCallBack()
异步回调
java
package com.pay.service.abstracts;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import java.util.Map;
/**
* Created by Calvin on 2019/5/11
* 异步回调-模板方法的抽象类
*/
@Slf4j
@Component
public abstract class AbstractPayCallbackTemplate {
/**
* 定义共同算法骨架
*
* 聚合支付-异步回调
* 1. 验签
* 2. 记录支付回调日志
* 3. 更改订单状态
*
* @return 支付结果
*/
public String asyncCallBack(){
// 1.支付回调参数验证。
Map<String,String> verifySignature = verifySignature();
// 2.参数验证成功,写入到日志中。
callBackPayLog(verifySignature);
String analysisCode = verifySignature.get("analysisCode");
if(!analysisCode.equals("200")){
return resultFail();
}
// 3. 执行回调异步相关逻辑
return asyncService(verifySignature);
}
/**
* 聚合支付-记录支付回调日志
*
* @param verifySignature 报文验签
*/
@Async
public void callBackPayLog(Map<String, String> verifySignature) {
log.info(">>>>>第二步:记录支付回调日志.....verifySignature:{}", verifySignature);
}
/**
* 聚合支付-验签(每个子类需要实现)
*
* @return 验证结果
*/
protected abstract Map<String, String> verifySignature();
/**
* 聚合支付-执行异步回调业务 (每个子类需要实现)
*
* @return 返回支付结果
*/
protected abstract String asyncService(Map<String, String> verifySignature);
/**
* 聚合支付-异步返回结果 (每个子类需要实现)
*
* @return 返回支付成功结果
*/
protected abstract String resultSuccess();
/**
* 聚合支付-异步返回失败(每个子类需要实现)
*
* @return 返回支付失败结果
*/
protected abstract String resultFail();
}
2. 将部分步骤的实现在子类中完成。
- 创建子类 :
- 支付宝回调实现类
AliPayCallbackServiceImpl.java
- 银联回调实现类
UnionPayCallbackServiceImpl.java
- 支付宝回调实现类
- 部分步骤行为:
- 验签
verifySignature()
- 执行异步回调业务
asyncService(Map<String, String> verifySignature)
- 支付成功
resultSuccess()
- 支付失败
resultFail()
- 验签
java
package com.pay.service.impl;
import com.pay.service.AliPayCallbackService;
import com.pay.service.abstracts.AbstractPayCallbackTemplate;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.Map;
/**
* Created by Calvin on 2019/5/11
*/
@Service
@Slf4j
public class AliPayCallbackServiceImpl extends AbstractPayCallbackTemplate implements AliPayCallbackService {
@Override
protected Map<String, String> verifySignature() {
/**
* 下面代码为伪代码:支付宝回调报文
*/
log.info(">>>>> 第一步:解析【支付宝】据报文.....verifySignature()");
Map<String, String> verifySignature = new HashMap<>();
verifySignature.put("price", "1399");
verifySignature.put("orderDes", "充值蚂蚁课堂永久会员");
// 支付状态为1表示为成功....
verifySignature.put("aliPayMentStatus", "1");
verifySignature.put("aliPayOrderNumber", "201910101011");
// 解析报文是否成功 200 为成功..
verifySignature.put("analysisCode", "200");
return verifySignature;
}
@Override
protected String asyncService(Map<String, String> verifySignature) {
log.info(">>>>> 第三步: 执行回调后的业务方法 asyncService() 参数 verifySignatureMap:{}", verifySignature);
String paymentStatus = verifySignature.get("aliPayMentStatus");
if (paymentStatus.equals("1")) {
String aliPayOrderNumber = verifySignature.get("aliPayOrderNumber");
log.info(">>>> orderNumber:{aliPayOrderNumber},已经支付成功 修改订单状态为已经支付...");
}
return resultSuccess();
}
@Override
protected String resultSuccess() {
return "【支付宝】 支付成功!";
}
@Override
protected String resultFail() {
return "【支付宝】 支付失败!";
}
}
java
package com.pay.service.impl;
import com.pay.service.UnionPayCallbackService;
import com.pay.service.abstracts.AbstractPayCallbackTemplate;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.Map;
@Service
@Slf4j
public class UnionPayCallbackServiceImpl extends AbstractPayCallbackTemplate implements UnionPayCallbackService {
@Override
protected Map<String, String> verifySignature() {
/**
* 下面代码为伪代码:银联支付回调报文
*/
log.info(">>>>>第一步:解析【银联】支付数据报文.....verifySignature()");
Map<String, String> verifySignature = new HashMap<>();
verifySignature.put("price", "1399");
verifySignature.put("orderDes", "充值蚂蚁课堂永久会员");
// 支付状态为1表示为成功....
verifySignature.put("paymentStatus", "1");
verifySignature.put("orderNumber", "201910101011");
// 解析报文是否成功 200 为成功..
verifySignature.put("analysisCode", "200");
return verifySignature;
}
@Override
protected String asyncService(Map<String, String> verifySignature) {
log.info(">>>>> 第三步: 执行回调后的业务方法 asyncService() 参数 verifySignatureMap:{}", verifySignature);
String paymentStatus = verifySignature.get("paymentStatus");
if (paymentStatus.equals("1")) {
String orderNumber = verifySignature.get("orderNumber");
log.info(">>>>orderNumber:{orderNumber},已经支付成功 修改订单状态为已经支付...");
}
return resultSuccess();
}
@Override
protected String resultSuccess() {
return "【银联】 支付成功!";
}
@Override
protected String resultFail() {
return "【银联】 支付失败!";
}
}
3. 编写聚合支付平台-回调接口
支付回调接口 :
PayCallbackController.java
参数支付回调模板类型:
templateId
- ALI_PAY
- UNION_PAY
请求接口 GET :
/pay/async/callback/{templateId}
返回异步回调结果:
asyncCallBack()
java
package com.pay.controller;
import com.pay.service.abstracts.AbstractPayCallbackTemplate;
import com.pay.factory.TemplateFactory;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping(value = "pay")
public class PayCallbackController {
/**
* 聚合支付平台-支付回调接口
* @param templateId 模板ID
* @return 支付回调结果
*/
@GetMapping("async/callback/{templateId}")
public String asyncCallBack(@PathVariable String templateId) {
AbstractPayCallbackTemplate payCallbackTemplate = TemplateFactory.getPayCallbackTemplate(templateId);
if (null == payCallbackTemplate) {
return "支付回调模板ID有误,没有相应的支付回调模板";
}
return payCallbackTemplate.asyncCallBack();
}
}
4. 创建工厂,根据对应支付回调模板类型,返回对应的类型支付回调结果。
创建一个枚举:
PayCallBackTemplateEnum.java
javapackage com.pay.enumeration; import lombok.AllArgsConstructor; import lombok.Getter; @Getter @AllArgsConstructor public enum PayCallbackTemplateEnum { ALI_PAY("com.pay.service.impl.AliPayCallbackServiceImpl"), UNION_PAY("com.pay.service.impl.UnionPayCallbackServiceImpl"), ; /** class 完整地址 **/ private String className; }
创建工厂:
TemplateFactory.java
,实例化对应的模板类型。javapackage com.pay.factory; import com.pay.enumeration.PayCallbackTemplateEnum; import com.pay.service.abstracts.AbstractPayCallbackTemplate; import com.pay.utils.ContextUtils; import lombok.extern.slf4j.Slf4j; /** * @Auther: Calvin * @Date: 2019/5/15 * @Description: */ @Slf4j public class TemplateFactory { public static AbstractPayCallbackTemplate getPayCallbackTemplate(String templateId){ AbstractPayCallbackTemplate abstractPayCallbackTemplate = null; // 1. 获取枚举中的ClassName try { String className = PayCallbackTemplateEnum.valueOf(templateId).getClassName(); // 2. 使用java 反射技术初始化类 abstractPayCallbackTemplate = (AbstractPayCallbackTemplate)Class.forName(className).newInstance(); } catch (Exception e) { log.error("============== 反射类不存在,错误:{} ====================", e.getMessage()); } return abstractPayCallbackTemplate; } }
6. 结果演示

控制台输出:
verilog
2020-09-03 23:40:09.762 INFO 3556 --- [nio-8081-exec-1] c.p.s.impl.AliPayCallbackServiceImpl : >>>>> 第一步:解析【支付宝】据报文.....verifySignature()
2020-09-03 23:40:19.577 INFO 3556 --- [nio-8081-exec-1] c.p.s.a.AbstractPayCallbackTemplate : >>>>>第二步:记录支付回调日志.....verifySignature:{aliPayOrderNumber=201910101011, orderDes=充值蚂蚁课堂永久会员, price=1399, analysisCode=200, aliPayMentStatus=1}
2020-09-03 23:40:33.757 INFO 3556 --- [nio-8081-exec-1] c.p.s.impl.AliPayCallbackServiceImpl : >>>>> 第三步: 执行回调后的业务方法 asyncService() 参数 verifySignatureMap:{aliPayOrderNumber=201910101011, orderDes=充值蚂蚁课堂永久会员, price=1399, analysisCode=200, aliPayMentStatus=1}
2020-09-03 23:40:36.058 INFO 3556 --- [nio-8081-exec-1] c.p.s.impl.AliPayCallbackServiceImpl : >>>> orderNumber:{aliPayOrderNumber},已经支付成功 修改订单状态为已经支付...
2020-09-03 23:41:13.135 INFO 3556 --- [nio-8081-exec-2] c.p.s.impl.UnionPayCallbackServiceImpl : >>>>>第一步:解析【银联】支付数据报文.....verifySignature()
2020-09-03 23:41:13.136 INFO 3556 --- [nio-8081-exec-2] c.p.s.a.AbstractPayCallbackTemplate : >>>>>第二步:记录支付回调日志.....verifySignature:{orderNumber=201910101011, orderDes=充值蚂蚁课堂永久会员, price=1399, analysisCode=200, paymentStatus=1}
2020-09-03 23:41:13.136 INFO 3556 --- [nio-8081-exec-2] c.p.s.impl.UnionPayCallbackServiceImpl : >>>>> 第三步: 执行回调后的业务方法 asyncService() 参数 verifySignatureMap:{orderNumber=201910101011, orderDes=充值蚂蚁课堂永久会员, price=1399, analysisCode=200, paymentStatus=1}
2020-09-03 23:41:13.136 INFO 3556 --- [nio-8081-exec-2] c.p.s.impl.UnionPayCallbackServiceImpl : >>>>orderNumber:{orderNumber},已经支付成功 修改订单状态为已经支付...
7. 模板模式—优缺点
优点:
缺点:
每个不同的实现都需要定义一个子类,这会导致类的个数的增加,设计更加抽象。