责任链模式

设计模式 总目录

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 老板审批,张老板
相关推荐
暗黑起源喵1 分钟前
设计模式-工厂设计模式
java·开发语言·设计模式
WaaTong6 分钟前
Java反射
java·开发语言·反射
九圣残炎39 分钟前
【从零开始的LeetCode-算法】1456. 定长子串中元音的最大数目
java·算法·leetcode
wclass-zhengge41 分钟前
Netty篇(入门编程)
java·linux·服务器
Re.不晚1 小时前
Java入门15——抽象类
java·开发语言·学习·算法·intellij-idea
雷神乐乐1 小时前
Maven学习——创建Maven的Java和Web工程,并运行在Tomcat上
java·maven
码农派大星。1 小时前
Spring Boot 配置文件
java·spring boot·后端
顾北川_野1 小时前
Android 手机设备的OEM-unlock解锁 和 adb push文件
android·java
江深竹静,一苇以航1 小时前
springboot3项目整合Mybatis-plus启动项目报错:Invalid bean definition with name ‘xxxMapper‘
java·spring boot
confiself2 小时前
大模型系列——LLAMA-O1 复刻代码解读
java·开发语言