高级点的 If else: 在Spring中使用责任链
Posted 嗡汤圆
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了高级点的 If else: 在Spring中使用责任链相关的知识,希望对你有一定的参考价值。
高级点的 If else: 在Spring中使用责任链
场景说明
背景
本文的背景: 需要开发一个微信公众号后台,对用户输入的关键词进行相应的回复。
如果采用传统的If else,会发现大量的判断分支和业务实现代码混合在同一个类中,在多人开发时候极易出现代码冲突,切代码难以阅读,同时在分支出现调整需求时也难以随心所欲的调整。因此需要一种模式能够将各个条件分支下的处理逻辑分离开来,并且做到可以随时配置调整。
难点
从上边的场景描述不难想到责任链设计模式,但是特殊的地方在于,我们的业务处理部分需要进行一些查询操作时候用到了Spring管理的一些服务类,需要注入到责任链处理节点中去。一般网络上找到的教程均为手动声明类,并初始化的情况,无法结合Spring的特性。后来找到了一篇文章描述了如何在Spring环境下使用责任链设计模式。链接在此
代码说明
要点
- 参考网关zuul 的filter配置风格,即包含: doParse, order, parserType三种关键参数,对于多种业务分支可以配置多种责任链
- Spring支持一次性将一个接口的所有实现类一次性载入进来
- 借用Ordered 接口 实现责任链的先后排序
关键代码
接口&抽象类
首先需要一个Parser的基础,就做一件事 doParse
/*
* 处理节点接口
*/
public interface ISupport
void doParse(ChainRequestWrapper wrapper) throws Exception;
/*
* 处理节点虚类
*/
public abstract AbsSupport implements ISupport, Ordered
protected AbsSupport support;
protected boolean shouldParse = false;// 默认不参与处理
protected String parserType;
protected int order = Ordered.LOWEST_PRECEDENCE;// 默认最低
// ...下边一堆 getter setter
/*
* 处理节点如餐
*/
public class ChainRequestWrapper
WxMsgDTO dto;
boolean shouldParse = true;// 默认载体内参与处理
// ... getter setter
以上,WxMsgDTO 的具体内容参考微信开发文档,一个XML描述的结构。一般用到了 fromUserName
,toUserName
,content
等字段。这里的shouldParse在每一个Support节点处理过程当中,一档处理完毕,不再继续往下传递时候,将其设置为false即可。
具体处理节点举例
这种节点继承AbsSupport虚类即可
/*
* 默认处理节点
*/
public class DefaultUnparseableSupport extends AbsSupport
// 构造函数的参数从配置文件获取
public DefaultUnparseableSupport(
@Value("$parser.defaultUnparseableSupport.shouldParse") boolean shouldParse,
@Value("$parser.defaultUnparseableSupport.order") int order,
@Value("$parser.defaultUnparseableSupport.parserType") String parserType,
)
// 以下都在虚类声明了
this.shouldParse = shouldParse;
this.order = order;
this.parserType = parserType;
@Override
public getOrder()
return this.order;
@Override
public boolean shouldParse(ChainRequestWrapper wrapper)
// 节点配置与传递参数配置共同决定
return wrapper.isShouldParse() && this.shouldParse;
@Override
public String getParserType()
return this.parserType;
@Override
public void doParse(ChainRequestWrapper wrapper) throws Exception
if(shouldParse(wrapper))
WxMsgDTOUtil.swapUserAndSetText(wrapper.getDto(), "默认处理响应");
wrapper.setShouldParse(false); // 这里设置false即不再参与链条的后续节点的处理
链条配置
根据上述代码在配置文件中配置 shouldParse, order, parserType等关键配置即可
parser.defaultUnparseableSupport.shouldParse=true
parser.defaultUnparseableSupport.order=9999 #默认节点排最低
parser.defaultUnparseableSupport.parserType=test
# .....
注入&使用
在程序启动时候注入链条,并在需要的地方使用即可
// 注入
@Component
public class SomeParserManager
List<AbsSupport> supportList;
public SomeParserManager(@Autowired List<AbsSupport> supportList)
// 这里将所有实现类一次性导入,并仅使用test类型的节点
this.supportList = supportList.stream().filter(item -> item.getParserType().equals("test")).collect(Collectors.toList());
Collections.sort(this.supportList,AnnotationAwareOrderCompareator.INSTANCE);
public void doParse(WxMsgDTO dto)
// 将微信传入消息封装为wrapper并交给责任链处理
ChainRequestWrapper wrapper = new ChainRequestWrapper();
wrapper.setDto(dto);
wrapper.setShouldParse(true);
for(AbsSupport support: supportList)
support.doParse(wrapper);
// 此时参数传递过程中wrapper内部值会随着处理节点的处理过程修改,最后直接使用wrapper即可
// toTextXmlString 是按照微信规范返回文字响应的封装方法,各位按需自行编写即可。
return wrapper.getDto().toTextXmlString();
总结
从原来的if else 分支改为责任链的好处在于,多人合作开发期间每个人负责的分支可以独立编写,而不会相互交织,并可以根据配置灵活改变分支的流程和先后顺序。
以上是关于高级点的 If else: 在Spring中使用责任链的主要内容,如果未能解决你的问题,请参考以下文章
在Spring boot项目中使用策略模式消除if-else
函数高级类型名别名if-else 的使用包的使用for循环swich的使用数组的使用
在 Spring Boot 中的 mockito 测试中的 if...else 语句问题