设计模式个人理解——责任链的运用

104 阅读4分钟

我正在参加「掘金·启航计划」

前言

责任链在工作中我用的没有策略模式多。也有点忘记了,打算先记录下来。如果说的地方有误人子弟的地方,望在评论区指出。

责任链的好处

这里我就不说明责任链是什么了,直接说明用的过程中体验到的好处

  1. 校验代码与其他代码分离,每个校验作为一个链上的独立个体,两个校验代码之间互不关联,增加了一定的灵活性(例如调整校验的顺序以及修改校验本身的逻辑)
  2. 添加/修改一个校验的时候无需修改原来使用校验的逻辑(例如活动报名方法使用了活动的一系列校验,后面需求改动要添加/修改活动某一个环节的校验时,无须修改活动报名方法)

责任链的坏处

  1. 需要注意责任链的配置。
  2. 复杂度提高,新增类比较多(个人感悟,如果校验过程不是很复杂,还是不要用责任链)

下面我用一个业务场景来使用责任链并展示责任链的好处
例如有一个业务是活动,有报名环节,用户报名的时候有三点需要验证。

  1. 是否重复报名
  2. 是否符合活动报名人数、报名时间。
  3. 用户本身是否符合活动要求,例如是否已充值报名、年龄是否符合活动要求等等

责任链实现

整体大概的思路是

  1. 先定义一个抽象的活动报名校验处理类(AbstractActivityRegisterHandler)
  2. 定义三个活动报名校验并继承AbstractActivityRegisterHandler
  3. 定义校验统一入口,并在启动的时候配置责任链
  4. 业务方法调用校验统一入口方法

前置处理

校验结果类

/**
 * 检查结果
 */
 @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("通过");
        }

    }

}

结果展示

image.png