模板+策略设计模式介绍及实战
1、设计模式介绍
1.1、模板模式
在模板模式(Template Pattern)中,一个抽象类公开定义了执行它的方法的方式/模板。它的子类可以按需要重写方法实现,但调用将以抽象类中定义的方式进行。这种类型的设计模式属于行为型模式。
1.1.1、介绍
**意图:**定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
**主要解决:**一些方法通用,却在每一个子类都重新写了这一方法。
**何时使用:**有一些通用的方法。
**如何解决:**将这些通用算法抽象出来。
**关键代码:**在抽象类实现,其他步骤在子类实现。
应用实例: 1、在造房子的时候,地基、走线、水管都一样,只有在建筑的后期才有加壁橱加栅栏等差异。 2、西游记里面菩萨定好的 81 难,这就是一个顶层的逻辑骨架。 3、spring 中对 Hibernate 的支持,将一些已经定好的方法封装起来,比如开启事务、获取 Session、关闭 Session 等,程序员不重复写那些已经规范好的代码,直接丢一个实体就可以保存。
优点: 1、封装不变部分,扩展可变部分。 2、提取公共代码,便于维护。 3、行为由父类控制,子类实现。
**缺点:**每一个不同的实现都需要一个子类来实现,导致类的个数增加,使得系统更加庞大。
使用场景: 1、有多个子类共有的方法,且逻辑相同。 2、重要的、复杂的方法,可以考虑作为模板方法。
**注意事项:**为防止恶意操作,一般模板方法都加上 final 关键词。
1.2、策略模式
在策略模式(Strategy Pattern)中,一个类的行为或其算法可以在运行时更改。这种类型的设计模式属于行为型模式。
在策略模式中,我们创建表示各种策略的对象和一个行为随着策略对象改变而改变的 context 对象。策略对象改变 context 对象的执行算法。
1.2.1、介绍
**意图:**定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换。
**主要解决:**在有多种算法相似的情况下,使用 if…else 所带来的复杂和难以维护。
**何时使用:**一个系统有许多许多类,而区分它们的只是他们直接的行为。
**如何解决:**将这些算法封装成一个一个的类,任意地替换。
**关键代码:**实现同一个接口。
应用实例: 1、诸葛亮的锦囊妙计,每一个锦囊就是一个策略。 2、旅行的出游方式,选择骑自行车、坐汽车,每一种旅行方式都是一个策略。 3、JAVA AWT 中的 LayoutManager。
优点: 1、算法可以自由切换。 2、避免使用多重条件判断。 3、扩展性良好。
缺点: 1、策略类会增多。 2、所有策略类都需要对外暴露。
使用场景: 1、如果在一个系统里面有许多类,它们之间的区别仅在于它们的行为,那么使用策略模式可以动态地让一个对象在许多行为中选择一种行为。 2、一个系统需要动态地在几种算法中选择一种。 3、如果一个对象有很多的行为,如果不用恰当的模式,这些行为就只好使用多重的条件选择语句来实现。
**注意事项:**如果一个系统的策略多于四个,就需要考虑使用混合模式,解决策略类膨胀的问题。
1.3、模板模式和策略模式的区别
- 模板模式一般只针对一套算法,注重对同一个算法的不同细节进行抽象提供不同的实现。而策略模式注重多套算法多套实现,在算法中间不应该有交集,因此算法和算法只间一般不会有冗余代码!
- 模板模式从头至尾,各个属性的位置都是固定的,是一个大而全的东西,固定了流程,按照模版来就行。各个抽象方法都是不重复的功能,有的渲染头部,有的选择底部。
- 策略模式是针对同一个算法,有不同的实现(或多个算法多个实现)。各个策略完成的功能,同一时间,只能选择其中的一种,即互斥的。
2、模板+策略设计模式实战
2.1、业务场景介绍
对接第三方服务服务,一共涉及到6个接口,特点如下:
- 六个接口路径不一致,
- 请求方式方法一致,
- 请求参数字段名称一样,
- 响应结构体一致,响应内容不一致。
2.2、代码实现
2.2.0、RuleType枚举
/**
* @Author
* @Date 2022/8/21 10:24
* @Description 类型
* @Version 1.0
*/
public enum RuleType {
/**
* @Author
* @Date Created in 17:15 2022/8/21
* @Description
* @Param
* @return
**/
sift,
/**
* image
* @Author
* @Date Created in 16:58 2022/8/30
* @Description
* @param
* @return
**/
quote,
/**
* automate
* @Author YangYaNan
* @Date Created in 11:57 2022/8/8
* @Description
* @param
* @return
**/
automate;
}
2.2.1、抽象基类BaseRuleType.java
/**
* @author :
* @date :Created in 11:21 2022/8/15
* @description :
* @version: 1.0
*/
@Service
@Slf4j
public abstract class BaseRuleType {
@Getter
public RuleType ruleType;
@Autowired
List<BaseRuleApi> baseRuleApis;
@Autowired
StringRedisTemplate stringRedisTemplate;
@Autowired
RuleConfigRepo ruleConfigRepo;
@Autowired
QuoteRecordRepo quoteRecordRepo;
/**
* handlerRule核心逻辑
* @Author YangYaNan
* @Date Created in 19:13 2022/8/15
* @Description
* @param ruleDecorator 规则
* @return void
**/
public abstract void handlerRule(IRuleDecorator ruleDecorator);
/**
* 解析规则结果
* @Author
* @Date Created in 12:55 2022/8/8
* @Description 目前使用
* @param ruleDecorator 规则
* @return java.lang.String
**/
public abstract void analyzeRuleData(IRuleDecorator ruleDecorator);
/**
* 挂载和ruleLog日志输出
* @Author
* @Date Created in 14:40 2022/8/17
* @Description
* @param quoteProtocol 挂载属主
* @param ruleDecorator 规则
* @return void
**/
public abstract void mountAndPrintLog(QuoteProtocol quoteProtocol, IRuleDecorator ruleDecorator);
/**
* commonHandlerRule公共核心逻辑
* @Author
* @Date Created in 19:13 2022/8/15
* @Description
* @param ruleDecorator
* @return void
**/
public void commonHandlerRule(IRuleDecorator ruleDecorator){
try {
if (RuleInfoKey.RULE_NOT_GROUPID.equals(ruleDecorator.getRuleGroupId())) {
log.info("[rule-{}-{}]不调用规则", ruleDecorator.getRuleType().toString(), ruleDecorator.getQuoteProtocol().getBusinessId());
ruleDecorator.getRuleLog().setCallRule(false);
return ;
}
baseRuleApis
.stream()
.filter(api -> api.supportType(ruleDecorator.getRuleType().toString()))
.findFirst()
.orElseThrow(() -> new CommonException(PARAMETER_ERROR.getCodeValue(), "暂不支持该类型规则"))
.callRule(ruleDecorator);
analyzeRuleData(ruleDecorator);
}catch (Exception e) {
log.error("[rule-{}-{}]调用规则异常:{},{}", ruleDecorator.getRuleType().toString(), ruleDecorator.getQuote().getBusinessId(), e.getMessage(), e.getStackTrace());
}
}
void printLog(IRuleDecorator ruleDecorator) {
ruleDecorator.getRuleLog().setEndAndConsumerTime(System.currentTimeMillis());
log.info("[rule-{}-{}]ruleLog:{}", ruleDecorator.getRuleType().toString(), ruleDecorator.getQuote().getBusinessId(), CacheUtil.doJacksonSerialize(ruleDecorator.getRuleLog()));
}
public long getLongByInteger(Map dataMap, String ruleCoverageCode) {
return dataMap.containsKey(ruleCoverageCode) ? ((Integer) dataMap.get(ruleCoverageCode)).longValue() : 1L;
}
public long getLongByDouble(Map dataMap, String ruleCoverageCode) {
return dataMap.containsKey(ruleCoverageCode) ? ((Double) dataMap.get(ruleCoverageCode)).longValue() : 1L;
}
public double getDoubleByDouble(Map dataMap, String ruleCoverageCode) {
return dataMap.containsKey(ruleCoverageCode) ? (Double) dataMap.get(ruleCoverageCode) : 1;
}
public double getDoubleByInteger(Map dataMap, String ruleCoverageCode) {
return dataMap.containsKey(ruleCoverageCode) ? ((Integer) dataMap.get(ruleCoverageCode)).longValue() : 1;
}
public Object getObjectFromResultData(Map dataMap, String sendforinspectionLevel) {
return dataMap.containsKey(sendforinspectionLevel) ? dataMap.get(sendforinspectionLevel) : "";
}
/**
* 去掉首位逗号
* @Author
* @Date Created in 16:26 2022/8/1
* @Description
* @param str 原字符串
* @return java.lang.String
**/
public String startAndEndCommaRemove(String str) {
String s = str.startsWith(",") ? str.replaceFirst(",", "") : str;
return s.endsWith(",") ? s.substring(0, s.length() - 1) : s;
}
public boolean isValidNumber(String key) {
String regx = "^\\d{4,6}$";
boolean isNumber = Pattern.compile(regx).matcher(key).find();
return isNumber;
}
void addAddActionRuleLog(RuleType.RuleTypeAction action, IRuleDecorator ruleDecorator, String ...changeInfoItems) {
StringBuilder changeInfo = new StringBuilder();
for (String s : changeInfoItems) {
changeInfo.append(s).append("--");
}
ruleDecorator.addRuleLog(action.name(), changeInfo.toString());
}
}
2.2.2、具体SiftType.java实现
/**
* @author :
* @date :Created in 11:24 2022/8/15
* @description :
* @version: 1.0
*/
@Service(value = "siftType")
@Slf4j
public class SiftType extends BaseRuleType {
public SiftType(){
this.ruleType = RuleType.sift;
}
@Override
public void handlerRule(IRuleDecorator ruleDecorator) {
commonHandlerRule(ruleDecorator);
}
/**
* 解析规则返回data
* @Author
* @Date Created in 11:56 2022/8/23
* @Description 目前添加险种使用
* @param ruleDecorator 报价
* @return
**/
@Override
public void analyzeRuleData(IRuleDecorator ruleDecorator){
List<Suite> suites = ruleDecorator.getSuites();
if (ObjectUtils.isEmpty(suites)){
log.info("[rule-{}-{}]单交强不动态添加险种:{},{}", RuleType.sift.toString(), ruleDecorator.getQuoteProtocol().getBusinessId());
return;
}
if (HttpStatus.HTTP_OK == ruleDecorator.getRuleResponse().getCode()) {
HashMap<String, Boolean> ruleSupportSuitMap = RuleSupportSuitType.getRuleSupportSuitMap();
suites.stream().forEach(suite -> { if (ruleSupportSuitMap.containsKey(suite.getCode())) { ruleSupportSuitMap.put(suite.getCode(), true); } });
addSiftSuites(ruleDecorator, ruleSupportSuitMap);
removeSiftSuites(ruleDecorator, ruleSupportSuitMap);
updateSiftSuites(ruleDecorator, ruleSupportSuitMap);
customizationSiftSuites(ruleDecorator, ruleSupportSuitMap);
}
}
@Override
public void mountAndPrintLog(QuoteProtocol quoteProtocol, IRuleDecorator ruleDecorator) {
if (ObjectUtils.isNotEmpty(quoteProtocol.getBaseSuiteInfo()) && ObjectUtils.isNotEmpty(quoteProtocol.getBaseSuiteInfo().getBizSuiteInfo())) {
quoteProtocol.getBaseSuiteInfo().getBizSuiteInfo().setSuites(ruleDecorator.getSuites());
quoteProtocol.setSq(ruleDecorator.getSq());
}
printLog(ruleDecorator);
}
private void addSiftSuites(IRuleDecorator ruleDecorator, Map<String, Boolean> ruleSupportSuitMap) {
//具体实现
}
private void customizationSiftSuites(IRuleDecorator ruleDecorator, Map<String, Boolean> ruleSupportSuitMap) {
//具体实现
}
private void updateSiftSuites(IRuleDecorator ruleDecorator, HashMap<String, Boolean> ruleSupportSuitMap) {
//具体实现
}
private void removeSiftSuites(IRuleDecorator ruleDecorator, HashMap<String, Boolean> ruleSupportSuitMap) {
//具体实现
}
}
2.2.3、具体AutomateType.java实现
/**
* @author :
* @date :Created in 11:28 2022/8/15
* @description :
* @version: 1.0
*/
@Service(value = "automateType")
@Slf4j
public class AutomateType extends BaseRuleType {
public AutomateType() {
this.ruleType = RuleType.automate;
}
@Override
public void handlerRule(IRuleDecorator ruleDecorator) {
commonHandlerRule(ruleDecorator);
}
@Override
public void analyzeRuleData(IRuleDecorator ruleDecorator) {
RuleResponse ruleResponse = ruleDecorator.getRuleResponse();
String specialsStr= "";
if (HttpStatus.HTTP_OK == ruleResponse.getCode()) {
Map dataMap = ruleResponse.getData();
specialsStr = dataMap.containsKey(RuleInfoKey.RULE_AUTOMATE_SPECIALLIST) ? dataMap.get(RuleInfoKey.RULE_AUTOMATE_SPECIALLIST).toString() : "";
addAddActionRuleLog(RuleType.RuleTypeAction.add, ruleDecorator, specialsStr);
}
ruleDecorator.setSpecialInfos(specialsStr);
}
@Override
public void mountAndPrintLog(QuoteProtocol quoteProtocol, IRuleDecorator ruleDecorator) {
printLog(ruleDecorator);
}
}
2.2.4、面向接口编程
/**
* @author :YangYaNan
* @date :Created in 18:20 2022/3/18
* @description :规则统一service接口
* @version: 1.0
*/
public interface IRuleManageService {
/**
* sift
* @Author
* @Date Created in 17:20 2022/8/21
* @Description
* @param quoteProtocol
* @return QuoteProtocol
**/
QuoteProtocol riskChangeRuleInfo(QuoteProtocol quoteProtocol);
}
2.2.5、策略调用RuleManageServiceImpl.java
/**
* @author :
* @date :Created in 18:22 2022/8/18
* @description :规则统一service层实现类
* @version: 1.0
*/
@Service
@Slf4j
public class RuleManageServiceImpl implements IRuleManageService {
@Autowired
private List<BaseRuleType> baseRuleTypes;
@Override
public QuoteProtocol riskChangeRuleInfo(QuoteProtocol quoteProtocol) {
IRuleDecorator ruleDecorator = new QuoteProtocolDecorator(quoteProtocol, RuleType.sift);
BaseRuleType baseRuleType = baseRuleTypes.stream()
.filter(api -> api.ruleType.equals(ruleDecorator.getRuleType()))
.findFirst()
.orElseThrow(() -> new CommonException(PARAMETER_ERROR.getCodeValue(), "暂不支持该类型"));
baseRuleType.handlerRule(ruleDecorator);
baseRuleType.mountAndPrintLog(quoteProtocol, ruleDecorator);
return quoteProtocol;
}
}