工厂+模板模式介绍及实战
1、设计模式介绍
1.1、工厂模式
工厂模式(Factory Pattern)是 Java 中最常用的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。
1.1.1、介绍
**意图:**定义一个创建对象的接口,让其子类自己决定实例化哪一个工厂类,工厂模式使其创建过程延迟到子类进行。
**主要解决:**主要解决接口选择的问题。
**何时使用:**我们明确地计划不同条件下创建不同实例时。
**如何解决:**让其子类实现工厂接口,返回的也是一个抽象的产品。
**关键代码:**创建过程在其子类执行。
应用实例: 1、您需要一辆汽车,可以直接从工厂里面提货,而不用去管这辆汽车是怎么做出来的,以及这个汽车里面的具体实现。 2、Hibernate 换数据库只需换方言和驱动就可以。
优点: 1、一个调用者想创建一个对象,只要知道其名称就可以了。 2、扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以。 3、屏蔽产品的具体实现,调用者只关心产品的接口。
**缺点:**每次增加一个产品时,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。这并不是什么好事。
使用场景: 1、日志记录器:记录可能记录到本地硬盘、系统事件、远程服务器等,用户可以选择记录日志到什么地方。 2、数据库访问,当用户不知道最后系统采用哪一类数据库,以及数据库可能有变化时。 3、设计一个连接服务器的框架,需要三个协议,“POP3”、“IMAP”、“HTTP”,可以把这三个作为产品类,共同实现一个接口。
**注意事项:**作为一种创建类模式,在任何需要生成复杂对象的地方,都可以使用工厂方法模式。有一点需要注意的地方就是复杂对象适合使用工厂模式,而简单对象,特别是只需要通过 new 就可以完成创建的对象,无需使用工厂模式。如果使用工厂模式,就需要引入一个工厂类,会增加系统的复杂度。
1.2、模板模式
在模板模式(Template Pattern)中,一个抽象类公开定义了执行它的方法的方式/模板。它的子类可以按需要重写方法实现,但调用将以抽象类中定义的方式进行。这种类型的设计模式属于行为型模式。
1.2.1、介绍
**意图:**定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
**主要解决:**一些方法通用,却在每一个子类都重新写了这一方法。
**何时使用:**有一些通用的方法。
**如何解决:**将这些通用算法抽象出来。
**关键代码:**在抽象类实现,其他步骤在子类实现。
应用实例: 1、在造房子的时候,地基、走线、水管都一样,只有在建筑的后期才有加壁橱加栅栏等差异。 2、西游记里面菩萨定好的 81 难,这就是一个顶层的逻辑骨架。 3、spring 中对 Hibernate 的支持,将一些已经定好的方法封装起来,比如开启事务、获取 Session、关闭 Session 等,程序员不重复写那些已经规范好的代码,直接丢一个实体就可以保存。
优点: 1、封装不变部分,扩展可变部分。 2、提取公共代码,便于维护。 3、行为由父类控制,子类实现。
**缺点:**每一个不同的实现都需要一个子类来实现,导致类的个数增加,使得系统更加庞大。
使用场景: 1、有多个子类共有的方法,且逻辑相同。 2、重要的、复杂的方法,可以考虑作为模板方法。
**注意事项:**为防止恶意操作,一般模板方法都加上 final 关键词。
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 :
* @date :Created in 10:23 2022/9/27
* @description :
* @version: 1.0
*/
public interface IRuleTypeFactory {
/**
* 获取接口类型
* @Author
* @Date Created in 10:24 2022/9/27
* @Description
* @param ruleType 接口类型
* @return com.cheche365.partner.service.impl.rule.type.BaseRuleType
**/
BaseRuleType getType(RuleType ruleType);
}
2.2.5、工厂RuleTypeFactoryImpl.java
/**
* @author :
* @date :Created in 10:28 2022/9/27
* @description :
* @version: 1.0
*/
@Service
public class RuleTypeFactoryImpl implements IRuleTypeFactory {
@Resource(name = "siftType")
private BaseRuleType siftType;
@Resource(name = "quoteType")
private BaseRuleType quoteType;
@Resource(name = "automateType")
private BaseRuleType automateType;
@Resource(name = "insureType")
private BaseRuleType insureType;
private static Map<RuleType, BaseRuleType> typeMap = new HashMap<>();
@PostConstruct
public void intiRuleType() {
typeMap.put(RuleType.sift, siftType);
typeMap.put(RuleType.quote, quoteType);
typeMap.put(RuleType.automate, automateType);
typeMap.put(RuleType.insure, insureType);
}
@Override
public BaseRuleType getType(RuleType ruleType) {
return typeMap.get(ruleType);
}
}
2.2.6、RuleManageServiceImpl.java
/**
* @author :
* @date :Created in 18:22 2022/9/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;
}
}