模板方法设计模式
介绍:
在面向对象系统的分析与设计过程中经常会遇到这样一种情况:对于某一个业务逻辑 (算法实现)在不同的对象中有不同的细节实现,但是逻辑(算法)的框架(或通用的应用 算法)是相同的。Template 提供了这种情况的一个实现框架。 Template 模式是采用继承的方式实现这一点:将逻辑(算法)框架放在抽象基类中,并 定义好细节的接口,子类中实现细节。【注释 1】
【注释 1】:Strategy 模式解决的是和 Template 模式类似的问题,但是 Strategy 模式是将逻辑 (算法)封装到一个类中,并采取组合(委托)的方式解决这个问题。
结构图:
模板方法的优缺点:
优点:
模板方法模式通过把不变的行为搬移到超类,去除了子类中的重复代码。子类实现算法的某些细节,有助于算法的扩展。通过一个父类调用子类实现的操作,通过子类扩展增加新的行为,符合“开放-封闭原则”。
缺点:
每个不同的实现都需要定义一个子类,这会导致类的个数的增加,设计更加抽象。
使用场景:
在某些类的算法中,用了相同的方法,造成代码的重复。控制子类扩展,子类必须遵守算法规则。
代码:
代码结构:
maven依赖
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.1.RELEASE</version> </parent> <dependencies> <!-- sprinboot web --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.16.10</version> </dependency> <dependency> <groupId>commons-lang</groupId> <artifactId>commons-lang</artifactId> <version>2.6</version> </dependency> </dependencies>
TemplateController
package com.ldq.controller; import com.ldq.AbstractPayCallbackTemplate; import com.ldq.factory.TemplateFactory; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; /** * @Auther: liangdeqiang * @Date: 2019-5-12 16:10 * @Description: */ @RestController public class TemplateController { @RequestMapping("/asyncCallBack") public String asyncCallBack(String templateId){ AbstractPayCallbackTemplate payCallbackTemplate = TemplateFactory.getPayCallbackTemplate(templateId); return payCallbackTemplate.asyncCallBack(); } }
TemplateFactory
package com.ldq.factory; import com.ldq.AbstractPayCallbackTemplate; import com.ldq.utils.SpringUtils; /** * @Auther: liangdeqiang * @Date: 2019-5-12 16:07 * @Description: */ public class TemplateFactory { /** * 使用工厂模式获取模板 * @param templateId * @return */ public static AbstractPayCallbackTemplate getPayCallbackTemplate(String templateId){ AbstractPayCallbackTemplate abstractPayCallbackTemplate = SpringUtils.getBean(templateId, AbstractPayCallbackTemplate.class); return abstractPayCallbackTemplate; } }
AliPayCallbackTemplate
package com.ldq.impl; import com.ldq.AbstractPayCallbackTemplate; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; import java.util.HashMap; import java.util.Map; /** * @Auther: liangdeqiang * @Date: 2019-5-12 16:02 * @Description: */ @Slf4j @Component public class AliPayCallbackTemplate extends AbstractPayCallbackTemplate { @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(); } private String resultSuccess() { return "success"; } @Override protected String resultFail() { return "fail"; } @Override protected Map<String, String> verifySignature() { //>>>>假设一下为阿里pay回调报文>>>>>>>>>>>>>>>> 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"); //>>>>假设一下为阿里pay回调报文结束>>>>>>>>>>>>>>>> // 解析报文是否成功 或者验证签名成功返回 200 为成功.. verifySignature.put("analysisCode", "200"); return verifySignature; } }
UnionPayCallbackTemplate
package com.ldq.impl; import com.ldq.AbstractPayCallbackTemplate; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; import java.util.HashMap; import java.util.Map; /** * @Auther: liangdeqiang * @Date: 2019-5-12 16:04 * @Description: */ @Slf4j @Component public class UnionPayCallbackTemplate extends AbstractPayCallbackTemplate { @Override protected String asyncService(Map<String, String> verifySignature) { log.info(">>>>>第三步 银联回调 asyncService()verifySignatureMap:{}", verifySignature); String paymentStatus = verifySignature.get("unionPayMentStatus"); if (paymentStatus.equals("1")) { String aliPayOrderNumber = verifySignature.get("aliPayOrderNumber"); log.info(">>>>orderNumber:{aliPayOrderNumber},已经支付成功 修改订单状态为已经支付..."); } return resultSuccess(); } @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("unionPayMentStatus", "1"); verifySignature.put("unionPayOrderNumber", "201910101011"); //>>>>假设一下为阿里pay回调报文结束>>>>>>>>>>>>>>>> // 解析报文是否成功 或者验证签名成功返回 200 为成功.. verifySignature.put("analysisCode", "200"); return verifySignature; } private String resultSuccess() { return "ok"; } @Override protected String resultFail() { return "fail"; } }
SpringUtils
package com.ldq.utils; import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.stereotype.Component; @Component public class SpringUtils implements ApplicationContextAware { private static ApplicationContext applicationContext; @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; } //获取applicationContext public static ApplicationContext getApplicationContext() { return applicationContext; } //通过name获取 Bean. public static Object getBean(String name) { return getApplicationContext().getBean(name); } //通过class获取Bean. public static <T> T getBean(Class<T> clazz) { return getApplicationContext().getBean(clazz); } //通过name,以及Clazz返回指定的Bean public static <T> T getBean(String name, Class<T> clazz) { return getApplicationContext().getBean(name, clazz); } }
AbstractPayCallbackTemplate
package com.ldq; import lombok.extern.slf4j.Slf4j; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import java.util.Map; /** * @Auther: liangdeqiang * @Date: 2019-5-12 15:53 * @Description: */ @Slf4j public abstract class AbstractPayCallbackTemplate { /** * 定义相同的骨架 * @return */ public String asyncCallBack(){ // 1.验证参数和验证签名 Map<String, String> verifySignature = verifySignature(); // 2.日志收集 相同 payLog(verifySignature); // 3. 获取验证签名状态 String analysisCode = verifySignature.get("analysisCode"); if(!"200".equals(analysisCode)){ return resultFail(); } // 4.更改数据库状态同时返回不同支付结果 return asyncService(verifySignature); } /** * 提交到数据库获取返回结果 * @param verifySignature * @return */ protected abstract String asyncService(Map<String,String> verifySignature); /** * 返回失败结果 * @return */ protected abstract String resultFail(); /** * 执行修改状态和返回不同的结果 * @param verifySignature */ @Async protected void payLog(Map<String,String> verifySignature){ log.info("写入数据库....verifySignature:{}",verifySignature); } protected abstract Map<String,String> verifySignature(); }
AppTemplate
package com.ldq; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.scheduling.annotation.Async; import org.springframework.scheduling.annotation.EnableAsync; /** * @Auther: liangdeqiang * @Date: 2019-5-12 16:12 * @Description: */ @SpringBootApplication @EnableAsync public class AppTemplate { public static void main(String[] args) { SpringApplication.run(AppTemplate.class); } }