我正在参加「掘金·启航计划」
前言
责任链在工作中我用的没有策略模式多。也有点忘记了,打算先记录下来。如果说的地方有误人子弟的地方,望在评论区指出。
责任链的好处
这里我就不说明责任链是什么了,直接说明用的过程中体验到的好处
- 校验代码与其他代码分离,每个校验作为一个链上的独立个体,两个校验代码之间互不关联,增加了一定的灵活性(例如调整校验的顺序以及修改校验本身的逻辑)
- 添加/修改一个校验的时候无需修改原来使用校验的逻辑(例如活动报名方法使用了活动的一系列校验,后面需求改动要添加/修改活动某一个环节的校验时,无须修改活动报名方法)
责任链的坏处
- 需要注意责任链的配置。
- 复杂度提高,新增类比较多(个人感悟,如果校验过程不是很复杂,还是不要用责任链)
下面我用一个业务场景来使用责任链并展示责任链的好处
例如有一个业务是活动,有报名环节,用户报名的时候有三点需要验证。
- 是否重复报名
- 是否符合活动报名人数、报名时间。
- 用户本身是否符合活动要求,例如是否已充值报名、年龄是否符合活动要求等等
责任链实现
整体大概的思路是
- 先定义一个抽象的活动报名校验处理类(AbstractActivityRegisterHandler)
- 定义三个活动报名校验并继承AbstractActivityRegisterHandler
- 定义校验统一入口,并在启动的时候配置责任链
- 业务方法调用校验统一入口方法
前置处理
校验结果类
/**
* 检查结果
*/
@Data
public class CheckResult {
/**
* 是否通过校验
*/
private Boolean pass;
/**
* 错误/成功信息
*/
private String message;
}
活动展示类
/**
* 活动展示类
*/
@Data
public class ActivityVO {
/**
* 活动名称
*/
private String name;
/**
* 报名开始时间
*/
private Date registerStartTime;
/**
* 报名结束时间
*/
private Date registerEndTime;
/**
* 限制成员人数
*/
private Long limitMember;
}
用户报名展示类
/**
* 用户报名(测试用)
*/
@Data
public class ActivityUserRegisterVO {
/**
* 用户名称
*/
private String name;
/**
* 报名时间
*/
private Date registerTime;
}
定义抽象的活动报名校验处理类
@Component
public abstract class AbstractActivityRegisterHandler {
//下一个校验的类
protected AbstractActivityRegisterHandler next;
//设置下一个校验的类
protected void setActivityRegisterHandler(AbstractActivityRegisterHandler handler){
this.next=handler;
}
/**
* 这里定义sort方法是为了后面配置责任链的时候,校验的顺序
* @return
*/
public abstract int getSort();
//子类需要实现的方法
public abstract CheckResult handler(ActivityVO activityVO,ActivityUserRegisterVO activityUserRegisterVO);
/**
* 调用下一个校验
* @param activityVO 活动展示类(展示活动的名称、报名时间、报名人数)
* @param activityUserRegisterVO 用户报名展示类(展示当前用户的姓名、报名时间)
* @return
*/
protected CheckResult next(ActivityVO activityVO,ActivityUserRegisterVO activityUserRegisterVO){
//如果为空,证明责任链已到达末端,返回成功
if(Objects.isNull(this.next)){
CheckResult checkResult=new CheckResult();
checkResult.setPass(true);
checkResult.setMessage("成功");
return checkResult;
}
return this.next.handler(activityVO,activityUserRegisterVO);
}
}
定义三个活动报名校验并继承AbstractActivityRegisterHandler
ActivityRepeatRegisterHandler:活动重复报名校验类
/**
* 活动重复报名
*/
@Component
public class ActivityRepeatRegisterHandler extends AbstractActivityRegisterHandler{
@Override
public int getSort() {
return 1;
}
@Override
public CheckResult handler(ActivityVO activityVO, ActivityUserRegisterVO activityUserRegisterVO) {
CheckResult result=new CheckResult();
System.out.println("检验是否有重复下单");
return super.next(activityVO,activityUserRegisterVO);
}
}
ActivityLimitCheckHandler:活动限制条件校验类
/**
* 活动限制条件(时间、限制人数)校验
*/
@Component
public class ActivityLimitCheckHandler extends AbstractActivityRegisterHandler{
@Override
public int getSort() {
return 2;
}
@Override
public CheckResult handler(ActivityVO activityVO, ActivityUserRegisterVO activityUserRegisterVO) {
CheckResult checkResult=new CheckResult();
//检测活动限制时间
if(activityUserRegisterVO.getRegisterTime().before(activityVO.getRegisterStartTime())||activityUserRegisterVO.getRegisterTime().after(activityVO.getRegisterEndTime())){
checkResult.setPass(false);
checkResult.setMessage("不符合活动报名时间");
return checkResult;
}
System.out.println("符合活动报名时间段");
//简单检测下限制人数
if(activityVO.getLimitMember()-1<0){
checkResult.setPass(false);
checkResult.setMessage("报名人数已满");
return checkResult;
}
System.out.println(activityUserRegisterVO.getName()+"满足报名人数");
return super.next(activityVO,activityUserRegisterVO);
}
}
ActivityUserCheckHandler:用户自身资格校验类
/**
* 参与人是否有资格参与活动检查
*/
@Component
public class ActivityUserCheckHandler extends AbstractActivityRegisterHandler {
@Override
public int getSort() {
return 3;
}
@Override
public CheckResult handler(ActivityVO activityVO, ActivityUserRegisterVO activityUserRegisterVO) {
System.out.println("检测用户是否付过钱");
System.out.println("检测用户是否符合活动要求");
return super.next(activityVO,activityUserRegisterVO);
}
}
定义校验统一入口,并在程序启动的时候配置责任链
/**
* 报名活动所需要的验证
*/
@Component
public class RegisterActivityChainService implements ApplicationContextAware {
private AbstractActivityRegisterHandler activityRegisterHandler;
/**
* 继承了ApplicationContextAware,Spring会注入一个applicationContext,
* 这里用来获取抽象类对应所有的子类
*/
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
//获取抽象类对应的所有子类
Map<String,AbstractActivityRegisterHandler> serviceMap= applicationContext.getBeansOfType(AbstractActivityRegisterHandler.class);
//提取子类并按sort方法进行排序
List<AbstractActivityRegisterHandler> list=serviceMap.values().stream().sorted(Comparator.comparing(AbstractActivityRegisterHandler::getSort)).collect(Collectors.toList());
if(CollectionUtils.isEmpty(list)){
System.out.println("抛出异常");
return;
}
//配置责任链
AbstractActivityRegisterHandler registerHandler=list.get(0);
activityRegisterHandler=registerHandler;
for (int i=1;i<list.size();i++){
registerHandler.setActivityRegisterHandler(list.get(i));
registerHandler=list.get(i);
}
}
/**
* 校验统一执行入口
*/
public CheckResult execute(ActivityVO activityVO,ActivityUserRegisterVO userRegisterVO){
return activityRegisterHandler.handler(activityVO,userRegisterVO);
}
}
测试类
@SpringBootTest
class ResponsibilityChainApplicationTests {
@Resource
private RegisterActivityChainService registerActivityChainService;
@Test
void contextLoads() throws ParseException {
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
//定义活动
ActivityVO activityVO=new ActivityVO();
activityVO.setName("活动1");
activityVO.setLimitMember(3L);
activityVO.setRegisterStartTime(formatter.parse("2022-10-30"));
activityVO.setRegisterEndTime(formatter.parse("2022-11-01"));
//用户A的报名
ActivityUserRegisterVO userRegisterVO=new ActivityUserRegisterVO();
userRegisterVO.setName("用户A");
userRegisterVO.setRegisterTime(new Date());
CheckResult result= registerActivityChainService.execute(activityVO,userRegisterVO);
if(!result.getPass()){
System.out.println("不通过,信息是:"+result.getMessage());
}else {
System.out.println("通过");
}
System.out.println("======================================");
//用户B的报名
ActivityUserRegisterVO userRegisterVO2=new ActivityUserRegisterVO();
userRegisterVO2.setName("用户B");
userRegisterVO2.setRegisterTime(formatter.parse("2022-10-28"));
CheckResult result2= registerActivityChainService.execute(activityVO,userRegisterVO2);
if(!result2.getPass()){
System.out.println("不通过,信息是:"+result2.getMessage());
}else {
System.out.println("通过");
}
}
}