什么是责任链?

描述

什么是责任链?

责任链模式是行为模式的一种,它将需要触发的Handler组成一条链,发送者将请求发给链的第一个接收者,并且沿着这条链传递,直到有一个Handler来处理它或者直到最后也没有对象处理而留在链末尾端;责任连模式的重点是在链上,由一条链去处理相似的请求,在链中决定谁来处理这个请求

责任链分为纯责任链与不纯责任链(一般实战应用较多)

**纯职责链 **

1.每个处理者接收到请求后,要么单纯转发请求,要么单纯处理请求。不允许既处理请求,又转发请求的情况。

2.请求必须被责任链上的某个处理者处理。不允许出现请求未被处理的情况。

**不纯职责链 **

1.每个处理者接收到请求后,除了单纯转发请求,或者单纯处理请求,还可以部分处理请求后,转发。

2.请求可以不被责任链上的任何处理者处理。

责任链优点

1.解耦请求者和处理者。

2.非常灵活,可以任意组装

3.各个节点的责任明确

缺点

1.每次都是从链头开始。

2. 可能造成死循环。责任链如果是环状的,可能会导致循环调用,造成死循环。

纯责任链的代码Demo:

/**
     * 在公司OA系统请假审批流程
    如果请假小于3天只需要项目经理批复就行;
    如果请假大于等于3天,小于7天需要人事经理批复了;
    如果请假大于等于7天,小于15天需要总经理批复了;
    如果申请请假大于等于15天,决绝批复......
     * @param args
     */
 public static void main(String[] args) {
        Leader manager = new Manager("张三");
        Leader hrManager = new HrManager("李四");
        Leader generalManager = new GeneralManager("王麻子");


        //组织责任链对象的关系
        manager.setNextLeader(hrManager);
        hrManager.setNextLeader(generalManager);
        //请假
        LeaveRequest request = new LeaveRequest("parry", 10, "回家相亲!");
        manager.dealLeaveRequest(request);
  }

public abstract class Leader {
    // 领导姓名
    protected String name;
    // 责任链上的后继对象
    protected Leader nextLeader;
    public Leader(String name) {
        super();
        this.name = name;
    }


    public void setNextLeader(Leader nextLeader) {
        this.nextLeader = nextLeader;
    }

    public abstract void dealLeaveRequest(LeaveRequest request);
}

  public class HrManager extends Leader{
      public HrManager(String name) {
          super(name);
      }


      @Override
      public void dealLeaveRequest(LeaveRequest request) {
        if (3 <= request.getLeaveDay() && request.getLeaveDay() < 7) {
            System.out.println("人事经理:" + name + " 审批了 " + request.getEmployee() + "请假" + request.getLeaveDay()
                    + "天的请求,请假原因:" + request.getReason());
        } else {
            if (this.nextLeader != null) {
                this.nextLeader.dealLeaveRequest(request);
            }
        }
    }
}


public class GeneralManager extends Leader {
    public GeneralManager(String name) {
        super(name);
    }


    @Override
    public void dealLeaveRequest(LeaveRequest request) {
        if (7 <= request.getLeaveDay() && request.getLeaveDay() <= 15) {
            System.out.println("总经理:" + name + " 审批了 " + request.getEmployee() + "请假" + request.getLeaveDay()
                    + "天的请求,请假原因:" + request.getReason());
        } else {
            System.out.println(
                    "总经理:" + name + " 拒绝了 " + request.getEmployee() + "请假" + request.getLeaveDay() + "天的请求,请假不能超过15天");
        }
    }
}


public class Manager extends Leader{
    public Manager(String name) {
        super(name);
    }


    @Override
    public void dealLeaveRequest(LeaveRequest request) {
        if (request.getLeaveDay() < 3) {
            System.out.println("经理:" + name + " 审批了 " + request.getEmployee() + "请假" + request.getLeaveDay()
                    + "天的请求,请假原因:" + request.getReason());
        } else {
            if (this.nextLeader != null) {
                this.nextLeader.dealLeaveRequest(request);
            }
        }
    }
}


@Data
public class LeaveRequest {
   //姓名
    private String name;
   //请假天数
    private int leaveDay;
    //请假原因
    private String reason;


    public LeaveRequest(String name, int leaveDay, String reason) {
        this.name=name;
        this.leaveDay=leaveDay;
        this.reason=reason;
    }  
}

电商售后使用责任链(不纯责任链)

售后业务梳理

电商售后常见三种模式:

仅退款、退款退货、退款换货

售后业务可分为

仅退款: 采购商申请——>商家审核——>完成

退款退货:采购商申请——>商家审核——>采购商发货——>商家确认收货——>完成

退款换货:采购商申请——>商家审核——>采购商发货——>商家确认收货——>商家发出新品——>采购商确认收货——>完成

仅退款的实际退款等操作在商家审核时,而退款退货和退款换货则在确认收货时。

以下为售后责任链流程:

售后->校验退款单状态->原路退款(以下单支付方式为准)->退积分或其它优惠->更新订单及对应商品退款信息->保存结算->保存财务流水->保存/更新退款日志->发送退款成功异步消息

三种售后的核心退款业务流程基本是一致的,少个别节点业务逻辑有所区别,将核心业务抽成责任链的各个节点,这对售后来说,代码的复用性提高了很多,同时业务处理更加清晰,犯错率大大降低。

以下为售后中代码使用Demo

定义一个节点的基类接口

public interface BaseRefundHandler {
    void handle(PipelineContext context); 
}

售后责任链组装,以下以仅退款为例

public class RefundPipeBean {
/**
 * 仅退款,责任链初始化节点
 */
public List<String> refundPipe = new ArrayList<>();


  public List<String> getRefundPipe() {
      refundPipe.add("checkRefundStatus"); //校验退款单状态
      refundPipe.add("refundMoney");  //原路退款(获取订单支付方式)
      refundPipe.add("returnScore");  //退积分或其它优惠券类
       ......
      return refundPipe;
  }


  @Bean
  @Scope("prototype")
  public CheckRefundStatus checkRefundStatus() {return new CheckRefundStatus();}

  @Bean
  @Scope("prototype")
  public RefundMoney refundMoney() {return new RefundMoney();}
  ......
}

** 注: 这个配置就等同于之前在xml里的配置**

"checkRefundStatus" class="com.xx.CheckRefundStatus"/>

创建一个启动监听器

@Component
public class RefundPipeListener extends ApplicationObjectSupport implements InitializingBean {
    private static Map<String, List> handlersMap = new HashMap<>();
     
   public static Map<String, List> getHandlersMap() {
        return handlersMap;
    }

    //最好定义成全局的,此处因演示 才在类中写 。 责任链的名称
   public static String ONLY_REFUND="ONLY_REFUND";
  @Override
  public void afterPropertiesSet() throws Exception {
    RefundPipeBean refundPipeBean=new RefundPipeBean();
     //装载退款业务链.....
    List normalHandlers=new ArrayList<>();

    for (String s : refundPipeBean.getRefundPipe()) {
        BaseRefundHandler normalHandler = (BaseRefundHandler) getApplicationContext().getBean(s);
        normalHandlers.add(normalHandler);
        handlersMap.put(ONLY_REFUND, normalHandlers);
    } 
  }
}

创建节点传递对象所用POJO类

@Data
public class PipelineContext<K, V> extends ConcurrentHashMap<K, V> {
    protected boolean success = false;
    //责任链结束标识
    protected boolean isEnd = false;
    protected String resultCode;
    private  Object data;


    public boolean isSuccess() {
        return success;
    }
    public void setSuccess(boolean success) {
        this.success = success;
    }


    public boolean isEnd() {
        return isEnd;
    }


    public void setEnd(boolean end) {
        isEnd = end;
    }
}


public class RefundPipelineContext<K, V> extends PipelineContext<K, V> {
    /**
     * 封装退款单信息
    */
    private RefundInfoPipeVo refundInfoPipeVo;


    public RefundInfoPipeVo getRefundInfoPipeVo() {
        return refundInfoPipeVo;
    }


    public void setRefundInfoPipeVo(RefundInfoPipeVo refundInfoPipeVo) {
        this.refundInfoPipeVo = refundInfoPipeVo;
    }
}

创建节点

public class CheckRefundStatus implements BaseRefundHandler {
  @Override
  public void handle(PipelineContext<String, RefundInfoPipeVo> context) {
     //业务逻辑 todo
     ......
   //表示该节点运行正常,可以继续向下走
   context.setSuccess(true);
  }
}

业务调用层

@RestController
public class RefundInfoController {
  @Autowired
  RefundInfoService refundInfoService;

  @ApiOperation("仅退款")
  @RequestMapping(value = "/auditRefund", method = {RequestMethod.GET, RequestMethod.POST}, produces = "application/json;charset=UTF-8")
  public RespData<Boolean> auditRefund(xxx) {
      refundInfoService.auditRefund(xxx);
      return RespData.success("审核成功",true);
  }
}


public interface RefundInfoService {
  void auditRefund(xxx);
}


@Service("refundInfoService")
public class RefundInfoServiceImpl implements RefundInfoService {


    @Override
    public void auditRefund(xxx) {
        //业务逻辑 todo 
        RefundInfoResultVo refundInfoResultVo = refundInfoMapper.queryById(platformId, refundId);
        ......
        PipelineContext<String, RefundInfoPipeVo> refund = new RefundPipelineContext<>();
        //在责任链中传递参数对象
        refund.put("refund", refundInfoResultVo);
        Map<String, List> map = RefundPipelineChangeListener.getHandlersMap();
        //通过责任链的名称获取对应链 。 此处key值应为一个全局的常量,与上面监听器中的链条名一致
        List baseRefundHandlers = map .get(ONLY_REFUND); 
        for (BaseRefundHandler handler : baseRefundHandlers) {
            handler.handle(refund);
            if (refund.isEnd()) {
                System.out.println("责任链执行结束...");
                break;
            }
            if (!refund.isSuccess()) {
                        System.out.println("责任链执行失败...");
                break;
            }
        }
    }
}

整体总结

以上是责任链在业务中创建及使用的流程。

同时以上流程也还存在一些可优化点:

  1. 责任链节点硬编码问题
  2. 添加同步事务控制
打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分