责任链模式

设计模式 总目录

https://preparedata.blog.csdn.net/article/details/134512591

文章目录

    • [设计模式 总目录](#设计模式 总目录)
    • 一、案例
    • 二、责任链
      • [2.1 责任链生成类](#2.1 责任链生成类)
      • [2.2 链路节点执行器 (基类,需要被继承)](#2.2 链路节点执行器 (基类,需要被继承))
    • [三、订单业务 责任链 (案例一)](#三、订单业务 责任链 (案例一))
      • [3.1 订单链抽象类 (组装链路、自定义订单公共方法)](#3.1 订单链抽象类 (组装链路、自定义订单公共方法))
      • [3.2 链路节点-参数检查](#3.2 链路节点-参数检查)
      • [3.3 链路节点-优惠券核销](#3.3 链路节点-优惠券核销)
      • [3.4 链路节点-积分抵扣](#3.4 链路节点-积分抵扣)
      • [3.5 链路节点-订单消息通知](#3.5 链路节点-订单消息通知)
      • [3.6 链路节点-处理购物车](#3.6 链路节点-处理购物车)
      • [3.7 链路节点-锁定库存](#3.7 链路节点-锁定库存)
    • [四、审批业务 责任链 (案例二)](#四、审批业务 责任链 (案例二))
      • [4.1 审批链抽象类 (组装链路、自定义审批公共方法)](#4.1 审批链抽象类 (组装链路、自定义审批公共方法))
      • [4.2 链路节点-老板审批](#4.2 链路节点-老板审批)
      • [4.3 链路节点-经理审批](#4.3 链路节点-经理审批)
    • 五、代码结构
    • 六、调用

一、案例

个人理解责任链模式在于,将业务功能拆分成各节点(职责节点),再打包成有顺序性的链路。
如果节点处理成功,可进入下一节点 。以下示例代码未包含此逻辑,但可在基类中添加状态来实现,偷个懒,暂不实现了。

案例一:订单创建

订单创建,可能会包含参数检查、锁定库存、优惠券核销、积分抵扣、处理购物车、订单消息通知等逻辑

但不同的订单类型可能包含的节点不同或顺序。现在可以将订单创建逻辑拆分。

不同的订单类型 可以提现设置不同的执行链路来处理订单。

如后续需添加节点或删除节点。也能快速适配

案例一:审批

审批流程,可能会包含组长、经理、行政、老板等逻辑

但不同的审批业务可能包含的节点不同或顺序。现在可以将逻辑拆分。

不同的审批业务 可以提现设置不同的执行链路来处理。

二、责任链

2.1 责任链生成类

利用泛型 T 来约束子类中需继承ResponsibilityChainPathExecute

利用泛型 P 来泛型化处理节点执行的参数, 实际业务中,可以将订单创建、审批相差很大的业务使用上下文来处理节点执行的参数

链路节点执行使用了递归 invoke(ResponsibilityChainPathExecute nextChain, P p) ,所以在组装链路时,需要保证链路有始有终,不能循环依赖

java 复制代码
package com.pd.shopping.order.designptern.chain;

/**
 * @author hl
 */
public class ResponsibilityChain<T extends ResponsibilityChainPathExecute, P> {

    /**
     * 责任链的开始节点
     */
    private T executeChain;

    /**
     * 构造函数
     * @param startChain 责任链的开始节点
     */
    public ResponsibilityChain(T startChain) {
        executeChain = startChain;
    }

    /**
     * 责任链的调用
     * @param p 执行方法的泛型参数
     */
    public void invoke(P p) {
        if(executeChain == null){
            return;
        }
        executeChain.execute(p);
        ResponsibilityChainPathExecute nextChain = executeChain.getNextChain();
        if(nextChain == null){
            return;
        }
        this.invoke(nextChain,p);
    }

    /**
     * 责任链后续节点执行 递归执行
     *
     * @param nextChain 责任链下一个节点
     * @param p 执行方法的泛型参数
     */
    private void invoke(ResponsibilityChainPathExecute nextChain, P p) {
        if(nextChain == null){
            return;
        }
        nextChain.execute(p);
        ResponsibilityChainPathExecute nextChain1 = nextChain.getNextChain();
        if(nextChain1 == null){
            return;
        }
        this.invoke(nextChain1, p);
    }
}

2.2 链路节点执行器 (基类,需要被继承)

需要使用责任链,都该继承ResponsibilityChainPathExecute,用来处理各节点的顺序执行

java 复制代码
package com.pd.shopping.order.designptern.chain;

import org.springframework.stereotype.Component;

/**
 * @author hl
 */
@Component
public abstract class ResponsibilityChainPathExecute<P> {

    /**
     * 责任链中节点执行方法
     * @param p 执行方法的泛型参数
     */
    public abstract void execute(P p);

    /**
     *
     */
    private ResponsibilityChainPathExecute nextChain;

    /**
     * 设置 责任链下一个节点
     * @param next 下一个节点
     */
    public void setNextChain(ResponsibilityChainPathExecute next){
        this.nextChain = next;
    }

    /**
     * 获取 责任链下一个节点
     *
     * @return ResponsibilityChainPathExecute 执行器
     */
    public ResponsibilityChainPathExecute getNextChain(){
        return this.nextChain;
    }
}

三、订单业务 责任链 (案例一)

3.1 订单链抽象类 (组装链路、自定义订单公共方法)

链路节点执行使用了递归,所以在组装链路时,需要保证链路有始有终,不能循环依赖

SpringApplicationUtil为获取Bean的工具类,暂不提供,但可以用new 创建一个Bean

java 复制代码
package com.pd.shopping.order.designptern.chain.order;

import com.pd.shopping.common.SpringApplicationUtil;
import com.pd.shopping.order.designptern.chain.*;
import org.springframework.stereotype.Component;

/**
 * @author hl
 */
@Component
public abstract class AbstractChainOrder<P> extends ResponsibilityChainPathExecute<P> {


    public static AbstractChainOrder chainPath(){
        //链开始节点 startCheck
        AbstractChainOrder startCheck = SpringApplicationUtil.getBean(ChainOrderCheck.class);
        AbstractChainOrder stock = SpringApplicationUtil.getBean(ChainOrderStock.class);
        AbstractChainOrder coupon = SpringApplicationUtil.getBean(ChainOrderCoupon.class);
        AbstractChainOrder integral = SpringApplicationUtil.getBean(ChainOrderIntegral.class);
        AbstractChainOrder shoppingCart = SpringApplicationUtil.getBean(ChainOrderShoppingCart.class);
        //链结束节点 endMsg
        AbstractChainOrder endMsg = SpringApplicationUtil.getBean(ChainOrderMsg.class);

        //链结束节点 endMsg
        shoppingCart.setNextChain(endMsg);
        integral.setNextChain(shoppingCart);
        coupon.setNextChain(integral);
        stock.setNextChain(coupon);
        //链开始节点 startCheck
        startCheck.setNextChain(stock);
        return startCheck;
    }

    public static AbstractChainOrder chainPath2(){
        //链开始节点 startCheck
        AbstractChainOrder startCheck = SpringApplicationUtil.getBean(ChainOrderCheck.class);
        AbstractChainOrder stock = SpringApplicationUtil.getBean(ChainOrderStock.class);
        //链结束节点 endMsg
        AbstractChainOrder endMsg = SpringApplicationUtil.getBean(ChainOrderMsg.class);

        stock.setNextChain(endMsg);
        startCheck.setNextChain(stock);
        return startCheck;
    }
}

3.2 链路节点-参数检查

java 复制代码
package com.pd.shopping.order.designptern.chain.order;

import org.springframework.stereotype.Component;
import java.util.Map;

/**
 * @author hl
 */
@Component
public class ChainOrderCheck extends AbstractChainOrder<Map<String, Object>> {

    @Override
    public void execute(Map<String, Object> map) {
        System.out.println("ChainOrderCheck 参数检查," + map.get("goodsName").toString());
    }
}

3.3 链路节点-优惠券核销

java 复制代码
package com.pd.shopping.order.designptern.chain.order;

import org.springframework.stereotype.Component;
import java.util.Map;

/**
 * @author hl
 */
@Component
public class ChainOrderCoupon extends AbstractChainOrder<Map<String, Object>> {

    @Override
    public void execute(Map<String, Object> map) {
        System.out.println("ChainOrderCoupon  优惠券核销," + map.get("goodsName").toString());
    }
}

3.4 链路节点-积分抵扣

java 复制代码
package com.pd.shopping.order.designptern.chain.order;

import org.springframework.stereotype.Component;
import java.util.Map;

/**
 * @author hl
 */
@Component
public class ChainOrderIntegral extends AbstractChainOrder<Map<String, Object>> {

    @Override
    public void execute(Map<String, Object> map) {
        System.out.println("ChainOrderIntegral 积分抵扣," + map.get("goodsName").toString());
    }
}

3.5 链路节点-订单消息通知

java 复制代码
package com.pd.shopping.order.designptern.chain.order;

import org.springframework.stereotype.Component;
import java.util.Map;

/**
 * @author hl
 */
@Component
public class ChainOrderMsg extends AbstractChainOrder<Map<String, Object>> {

    @Override
    public void execute(Map<String, Object> map) {
        System.out.println("ChainOrderMsg 订单消息通知," + map.get("goodsName").toString());
    }
}

3.6 链路节点-处理购物车

java 复制代码
package com.pd.shopping.order.designptern.chain.order;

import org.springframework.stereotype.Component;
import java.util.Map;

/**
 * @author hl
 */
@Component
public class ChainOrderShoppingCart extends AbstractChainOrder<Map<String, Object>> {

    @Override
    public void execute(Map<String, Object> map) {
        System.out.println("ChainOrderShoppingCart 处理购物车," + map.get("goodsName").toString());
    }
}

3.7 链路节点-锁定库存

java 复制代码
package com.pd.shopping.order.designptern.chain.order;

import org.springframework.stereotype.Component;
import java.util.Map;

/**
 * @author hl
 */
@Component
public class ChainOrderStock extends AbstractChainOrder<Map<String, Object>> {

    @Override
    public void execute(Map<String, Object> map) {
        System.out.println("ChainOrderStock 锁定库存," + map.get("goodsName").toString());
    }
}

四、审批业务 责任链 (案例二)

4.1 审批链抽象类 (组装链路、自定义审批公共方法)

链路节点执行使用了递归,所以在组装链路时,需要保证链路有始有终,不能循环依赖

java 复制代码
package com.pd.shopping.order.designptern.chain.approve;

import com.pd.shopping.common.SpringApplicationUtil;
import com.pd.shopping.order.designptern.chain.ResponsibilityChainPathExecute;
import org.springframework.stereotype.Component;

/**
 * @author hl
 */
@Component
public abstract class AbstractChainApprove<P> extends ResponsibilityChainPathExecute<P> {

    public static AbstractChainApprove chainPath(){
        //链开始节点 startLeader
        AbstractChainApprove startLeader = SpringApplicationUtil.getBean(ChainApproveLeader.class);
        //链结束节点 endBoos
        AbstractChainApprove endBoos = SpringApplicationUtil.getBean(ChainApproveBoos.class);

        //链开始节点 startLeader
        startLeader.setNextChain(endBoos);
        return startLeader;
    }
}

4.2 链路节点-老板审批

java 复制代码
package com.pd.shopping.order.designptern.chain.approve;

import com.pd.shopping.order.model.bo.ApproveContext;
import org.springframework.stereotype.Component;

/**
 * @author hl
 */
@Component
public class ChainApproveBoos extends AbstractChainApprove<ApproveContext> {

    @Override
    public void execute(ApproveContext context) {
        System.out.println("ChainApproveBoos 老板审批," + context.getBoosName());
    }
}

4.3 链路节点-经理审批

java 复制代码
package com.pd.shopping.order.designptern.chain.approve;

import com.pd.shopping.order.model.bo.ApproveContext;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

/**
 * @author hl
 */
@Slf4j
@Component
public class ChainApproveLeader extends AbstractChainApprove<ApproveContext> {

    @Override
    public void execute(ApproveContext context) {
        System.out.println("ChainApproveBoos 经理审批," + context.getLeaderName());
    }
}

五、代码结构

六、调用

java 复制代码
@GetMapping("/chainOrder")
public void chainOrder() {

    System.out.println("订单创建,链路1:");
    //下单参数
    Map<String,Object> map1 = new HashMap<>();
    map1.put("goodsName","比亚迪");
    //链路
    AbstractChainOrder chain1 = AbstractChainOrder.chainPath();
    ResponsibilityChain responsibilityChain1 = new ResponsibilityChain<AbstractChainOrder, Map<String,Object>>(chain1);
    responsibilityChain1.invoke(map1);


    System.out.println("订单创建,链路2:");
    Map<String,Object> map2 = new HashMap<>();
    map2.put("goodsName","长城");
    AbstractChainOrder chain2 = AbstractChainOrder.chainPath2();
    ResponsibilityChain responsibilityChain2 = new ResponsibilityChain<AbstractChainOrder, Map<String,Object>>(chain2);
    responsibilityChain2.invoke(map2);

    /* ********************************************************************** */

    System.out.println("审批,链路2:");
    ApproveContext approveContext = new ApproveContext();
    approveContext.setBoosName("张老板");
    approveContext.setLeaderName("李经理");
    AbstractChainApprove chainApprove = AbstractChainApprove.chainPath();
    ResponsibilityChain responsibilityChain3 = new ResponsibilityChain<AbstractChainApprove, ApproveContext>(chainApprove);
    responsibilityChain3.invoke(approveContext);

}

执行日志

java 复制代码
订单创建,链路1:
ChainOrderCheck 参数检查,比亚迪
ChainOrderStock 锁定库存,比亚迪
ChainOrderCoupon  优惠券核销,比亚迪
ChainOrderIntegral 积分抵扣,比亚迪
ChainOrderShoppingCart 处理购物车,比亚迪
ChainOrderMsg 订单消息通知,比亚迪
订单创建,链路2:
ChainOrderCheck 参数检查,长城
ChainOrderStock 锁定库存,长城
ChainOrderMsg 订单消息通知,长城

审批,链路2:
ChainApproveBoos 经理审批,李经理
ChainApproveBoos 老板审批,张老板
相关推荐
V+zmm101341 分钟前
社区二手物品交易小程序ssm+论文源码调试讲解
java·微信小程序·小程序·毕业设计·ssm
坊钰4 分钟前
【Java 数据结构】合并两个有序链表
java·开发语言·数据结构·学习·链表
秋天下着雨10 分钟前
apifox调用jar程序
java·python·jar
m0_7482510815 分钟前
docker安装nginx,docker部署vue前端,以及docker部署java的jar部署
java·前端·docker
A227416 分钟前
Redis——缓存雪崩
java·redis·缓存
Mr.朱鹏17 分钟前
操作002:HelloWorld
java·后端·spring·rabbitmq·maven·intellij-idea·java-rabbitmq
顽疲38 分钟前
从零用java实现 小红书 springboot vue uniapp (6)用户登录鉴权及发布笔记
java·vue.js·spring boot·uni-app
oscar9991 小时前
Maven项目中不修改 pom.xml 状况下直接运行OpenRewrite的配方
java·maven·openrewrite
南宫生1 小时前
力扣-数据结构-3【算法学习day.74】
java·数据结构·学习·算法·leetcode
工业甲酰苯胺1 小时前
聊一聊 C#线程池 的线程动态注入
java·开发语言·c#