责任链设计模式

责任链模式

顾名思义,就是链式的去处理一个请求或者任务,收到请求后, 每个处理者均可对请求进行处理, 或将其传递给链上的下个处理者。

  

应用场景

  1. 一个请求需要多种类型的处理
  2. 各个处理之间,相对独立
  3. 需要指定多种处理的处理顺序

实际举例

  1. 打印日志的时候,我们可能定义了多个logger
  2. Netty在接收和发送数据时,需要经过多个Handler的处理,也是责任链的场景
  3. 用户登录的时候,需要校验密码、用户状态、是否认证等流程,也是可以采用责任链的场景
  4. 多条件流程判断:权限控制  
  5. ERP 系统流程审批:总经理、人事经理、项目经理  
  6. Java 过滤器 的底层实现 Filter

如果不使用该设计模式,那么当需求有所改变时代码会变得臃肿或者难以维护。例如一个游戏有100关,我们的代码很可能就会写成这个样子:

if(第1关通过){
    // 第2关 游戏
    if(第2关通过){
        // 第3关 游戏
        if(第3关通过){
           // 第4关 游戏
            if(第4关通过){
                // 第5关 游戏
                if(第5关通过){
                    // 第6关 游戏
                    if(第6关通过){
                        //...
                    }
                }
            } 
        }
    }
}

对上述例子改造

程序结构:

定义链式节点操作:

public interface HandlerChain {

    /**
     * 执行下一个链式节点的处理
     * @param bizParamDTO
     * @throws Exception
     */
    void nextNodeDeal(BizParamDTO bizParamDTO) throws Exception;

    /**
     * 开始链式节点的处理
     * @param bizParamDTO
     * @return
     */
    ChainResultDTO doChainDeal(BizParamDTO bizParamDTO);

}
@Slf4j
@Component
public class MockHandlerChain implements HandlerChain {

    SpringUtil springUtil;

    private final List<Handler> handlers;

    private Iterator<Handler> iterator;

    public MockHandlerChain(SpringUtil springUtil) {
        this.springUtil = springUtil;
        this.handlers = initFilterList();
        this.iterator = this.handlers.iterator();
    }

    private  List<Handler> initFilterList() {
        //获取带类主键@ChainDealPattern的类数组
        Object[] handlerFactories = springUtil.getBeansByAnnotation(ChainDealPattern.class);

        //按order进行排序
        List<HandlerProxy> handlerProxies = Arrays.stream(handlerFactories).map(d -> {
            ChainDealPattern annotation = d.getClass().getAnnotation(ChainDealPattern.class);
            Handler handle = (Handler) d;
            HandlerProxy handlerProxy = new HandlerProxy(annotation.order(), handle);
            return handlerProxy;
        }).sorted(Comparator.comparing(HandlerProxy::getOrder)).collect(Collectors.toList());

        //返回处理的Handler列表
        return handlerProxies.stream().map(d -> d.getHandle()).collect(Collectors.toList());
    }

    @Override
    public void nextNodeDeal(BizParamDTO bizParamDTO) throws Exception {
        if (this.iterator.hasNext()) {
            Handler nextHandler = this.iterator.next();
            nextHandler.doHandle(bizParamDTO, this);
        }
    }

    @Override
    public ChainResultDTO doChainDeal(BizParamDTO bizParamDTO) {
        ChainResultDTO chainResultDTO;
        try {
            this.nextNodeDeal(bizParamDTO);
            chainResultDTO = ChainResultDTO.builder().success(true).build();
        } catch (ChainException e) {
            chainResultDTO = ChainResultDTO.builder().success(false).msg(e.getMsg()).data(bizParamDTO).build();
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            chainResultDTO = ChainResultDTO.builder().success(false).msg(e.getMessage()).data(bizParamDTO).build();
        }


        return chainResultDTO;
    }

    private static final class HandlerProxy {
        int order;
        Handler handle;

        public HandlerProxy(int order, Handler handle) {
            this.order = order;
            this.handle = handle;
        }

        public int getOrder() {
            return order;
        }

        public void setOrder(int order) {
            this.order = order;
        }

        public Handler getHandle() {
            return handle;
        }

        public void setHandle(Handler handle) {
            this.handle = handle;
        }
    }
}
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface ChainDealPattern {
    int order() default 0;
    String value() default "default";
}

定义:链式的每个节点处理

import com.dt.mvp.myc.service.biz.responsiblechain.chain.HandlerChain;
import com.dt.mvp.myc.service.biz.responsiblechain.dto.BizParamDTO;

public interface Handler {

    void doHandle(BizParamDTO parameters, HandlerChain chain) throws Exception;

}

第一个节点,判断

@Slf4j
@Component
@ChainDealPattern(value = "first", order = 50)
public class FirstBizHandle implements Handler {

    @Override
    public void doHandle(BizParamDTO parameters, HandlerChain chain) throws Exception {
        log.info("doHandle execute in " + this.getClass());
        int limit = 100;

        if (parameters.getLength() > limit) {
            throw new ChainException("长度超百");
        }
        //继续执行链式操作
        chain.nextNodeDeal(parameters);
    }

}

第二个节点,判断

@Slf4j
@Component
@ChainDealPattern(value = "second", order = 20)
public class SecondBizHandle implements Handler {

    @Override
    public void doHandle(BizParamDTO parameters, HandlerChain chain) throws Exception {
        log.info("doHandle execute in " + this.getClass());

        if (parameters.getName() == null) {
            throw new ChainException("名称不能为空");
        }
        //继续执行链式操作
        chain.nextNodeDeal(parameters);
    }

}

第三个节点,判断

@Slf4j
@Component
@ChainDealPattern(value = "third", order = 30)
public class ThirdBizHandle implements Handler {


    @Override
    public void doHandle(BizParamDTO parameters, HandlerChain chain) throws Exception {
        log.info("doHandle execute in " + this.getClass());

        if (!parameters.getFlag()) {
            throw new ChainException("成功标识为假");
        }
        //继续执行链式操作
        chain.nextNodeDeal(parameters);
    }

}

第N个节点,判断  。。。
在Service上调用:

@Slf4j
@Service
@AllArgsConstructor
public class BizService {

    HandlerChain handlerChain;

    /**
     * 业务处理,里边采了用链式业务处理
     * @param paramDTO
     * @return
     */
    public ChainResultDTO bizDeal(BizParamDTO paramDTO) {
       return handlerChain.doChainDeal(paramDTO);
    }

}

 

posted on 2023-02-22 18:15  蔻德盈  阅读(22)  评论(0)    收藏  举报