设计模式之模板模式
定义: 定义一个操作的算法骨架,而将一些步骤延迟到子类中。Template method 使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤
应用场景:
- 当你想让客户端只扩展算法的特定步骤时,而不是整个算法或其结构时
- 当你有几个类包含几乎形同的算法,但有一些细微的差异时
优点:
- 你可以让客户端只覆盖大型算法的某些部分,从而减少算法其他部分发生的更改对他们的影响
- 你可以将重复的代码拖放到超类中
可以参考:
- javax.servlet.http.HttpServlet
- org.springframework.web.servlet.mvc.AbstractController
今天我们说下模板模式在实际项目中使用的场景之一,话补多少直接上代码
/**
* 定义下我们的主体代码
*/
@Slf4j
@Service
public abstract class AbstractPayPatternService {
/**
* 实际支付方法
* @param orderNo
* @param pattern
* @return
*/
public String doPay(String orderNo, String pattern) {
//1.根据订单号 获取订单相关信息
//2.验证参数 传入订单对象验证相关参数
checkData(null);
//3.支付前参数组装,返回相关的map组装信息 入参是订单相关参数
Map<String,Object> map = verifySignature(null);
//4.执行对相应的支付方式 service
String result = executeService(map);
//5.异步部写入操作日志
writeLog(null);
return "SUCCESS";
}
/**
* 支付时 参数校验
* @param object
* @return
*/
public void checkData(Object object){
log.info("参数验证");
}
/**
* 写入操作日志
* @param object
*/
public final void writeLog(Object object){
log.info("异步写入操作日志信息");
}
/**
* 支付前 参数准备
* @param object
* @return
*/
protected abstract Map<String,Object> verifySignature(Object object);
/**
* 业务执行
* @param map
* @return
*/
protected abstract String executeService(Map<String,Object> map);
}
现在我们去编写相关业务的执行代码,这里实现 InitializingBean 主要是想换一种方式标记当前类,当然你也可以使用@Service(“XXXXX”)来标记当类的唯一标识,这里只做一个实现类,如果其他的支付方式 可以自己另行创建实现
/**
* @author lgl
* @date 2021/9/1
*/
@Slf4j
@Service
public class WechatPayServiceImpl extends AbstractPayPatternService implements InitializingBean {
@Override
protected Map<String, Object> verifySignature(Object object) {
log.info("微信方支付参数认证和签名");
return new HashMap<>(0);
}
@Override
protected String executeService(Map<String, Object> map) {
log.info("微信支付接口调用和业务处理");
return "OK";
}
@Override
public void afterPropertiesSet() throws Exception {
SpringUtil.STATE_MAP.put("wechatPay","wechatPayServiceImpl");
}
}
/**
* @author lgl
* @date 2021/8/31
*/
@Slf4j
@Component
public class SpringUtil implements ApplicationContextAware {
private static ApplicationContext context;
/**
* 状态与类名的映射
*/
public static Map<String,String> STATE_MAP = new HashMap<>();
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
SpringUtil.context = applicationContext;
}
/**
* 获取上下文对象
* @return
*/
public static ApplicationContext getContext(){
return context;
}
/**
* 根据name获取对象bean
* @param name
* @return
*/
public static Object getBean(String name){
return getContext().getBean(name);
}
/**
* 根据class获取对象bean
* @param clazz
* @param <T>
* @return
*/
public static <T> T getBean(Class<T> clazz){
return getContext().getBean(clazz);
}
/**
* 根据name 以及对象指定返回bean
* @param name
* @param clazz
* @param <T>
* @return
*/
public static <T> T getBean(String name,Class<T> clazz){
//改造前: name是之具体的类名
//改造后:name为状态映射类名 这样前端直接传具体的状体就可以了 也可以把该参数维护成枚举
String clsName = STATE_MAP.get(name);
return getContext().getBean(clsName,clazz);
}
}
```java
/**
* 其中pattern可以是你实现类的唯一标识 或者是映射后的参数 当然也可以使用枚举类做标识映射
* @author lgl
* @date 2021/9/1
*/
@RestController
@RequestMapping("pay")
public class PayPatternController {
@GetMapping("pay")
public String payOrder(String payPattern){
AbstractPayPatternService bean = SpringUtil.getBean(payPattern, AbstractPayPatternService.class);
String result = bean.doPay("O9876", payPattern);
return result;
}
}
标记类方法 也可以参考上一篇的状态模式篇 小编尽量在以后的创作中使用不同的实现方式