Java 设计模式-责任链模式

1、定义

责任链模式是一种行为设计模式,允许你将请求沿着处理链发送,然后处理者都可对其进行处理,完成后可以再将其传递给下一个处理者。

  • 可以控制请求的处理的顺序
  • 单一职责原则,可以对发起操作和执行操作的类进行解耦
  • 开闭原则,可不用修改原有的业务代码,新增其他的处理类
  • 不能保证每个处理者者可以执行
  • 效率不是很好,调用时如果不注意会出现各种各样的问题

2、使用场景

  • 当必须按顺序执行多个处理者时,可以考虑使用责任链模式
  • 如果处理者的顺序及其必须在运行时改变时,可以考虑使用责任链模式

实际应用:

  • Apache Tomcat 对 Encoding 编码处理的处理
  • SpringBoot ⾥⾯的拦截器、过滤器链
  • netty 中的处理链
  • 支付风控的机制
  • ⽇志处理级别

3、Java中简单应用

使用场景:

以请假审批系统为例,组长 → 总监→ 部长形成了一条链
职员提交请假申请后,请求会沿着这条链传递,直到有对象可以处理它。
一个5天的请假申请,先到达组长处;
组长无权限审批,传递请求到自己的上级(总监);
总监有权限审批,于是同意了该请假申请
作为请求的发送者,职员无需关心最终由谁审批,只需要提交请求即可

3.1抽象处理接口


/**
 * @Author charles.yao
 * @Description 抽象处理者
 * @Date 2022/12/21 15:32
 */
public interface Hanlder {
    /**
     * 处理员工请假天数
     * @param name
     * @param holidayDay
     */
    public abstract void handleRequest(String name, Integer holidayDay);
}

3.2创建组长、总监、部长三个具体处理者,实现具体的处理逻辑


/**
 * @Author charles.yao
 * @Description 组长处理者
 * @Date 2022/12/21 15:34
 */
public class PmHandler extends Hanlder {

    @Override
    public void handleRequest(String name, Integer holidayDay) {
        if (holidayDay <= 3) {
            System.out.println(name + "组长已经批准假期");
        } else {
            if (getNext() != null) {
                getNext().handleRequest(name,holidayDay);
            }else {
                System.out.println("请假天数太多,申请被驳回");
            }
        }

    }
}


/**
 * @Author charles.yao
 * @Description 部门经理处理者
 * @Date 2022/12/21 15:37
 */
public class MinisterHandler extends Hanlder{
    @Override
    public void handleRequest(String name, Integer holidayDay) {
        if (holidayDay <= 15) {
            System.out.println(name + "部门经理已经批准假期");
        } else {
            if (getNext() != null) {
                getNext().handleRequest(name,holidayDay);
            }else {
                System.out.println("请假天数太多,申请被驳回");
            }
        }
    }
}



/**
 * @Author charles.yao
 * @Description 总监处理者
 * @Date 2022/12/21 15:37
 */
public class DirectorHandler extends Hanlder{
    @Override
    public void handleRequest(String name, Integer holidayDay) {
        if (holidayDay <= 7) {
            System.out.println(name + "总监已经批准假期");
        } else {
            if (getNext() != null) {
                getNext().handleRequest(name,holidayDay);
            }else {
                System.out.println("请假天数太多,申请被驳回");
            }
        }
    }
}

测试类


/**
 * @Author charles.yao
 * @Description
 * @Date 2022/12/21 15:39
 */
public class OaTest1 {
    public static void main(String[] args) {
        Hanlder pmHandler = new PmHandler();
        Hanlder directorHandler = new DirectorHandler();
        Hanlder ministerHandler = new MinisterHandler();
        pmHandler.setNext(directorHandler);
        directorHandler.setNext(ministerHandler);
        pmHandler.handleRequest("张三",14);

    }
}

运行结果

张三部门经理已经批准假期

通过以上简单的小demo,我们会发现一系列问题:如果对具体处理者得增加、减少或者调整顺序,都涉及整个责任链得调整 重构,反而增加没必要得工作量,我们对上边写法进行改进,改进如下,

    • 取消抽象处理者中的next引用
    • 单独的责任链类:
      • 提供添加具体处理者的add方法,基于List构建隐形的责任链;
      • 实现抽象处理者的请求处理方法,遍历责任链中的具体处理者,以实现请求的传递与处理
// 抽象处理者
public interface Handler {
    public abstract void handleRequest(String name, int days);
}

// 具体处理者
public class PMHandler implements Handler {
    @Override
    public void handleRequest(String name, int days) {
        if (days <= 3) {
            System.out.println(name +",组长已经同意您的请假审批!");
        }
    }
}

public class DirectorHandler implements Handler {
    @Override
    public void handleRequest(String name, int days) {
        if (days <= 7) {
            System.out.println(name + ",中心总监已经同意您的请假审批");
        }
    }
}

public class MinisterHandler implements Handler {
    @Override
    public void handleRequest(String name, int days) {
        if (days <= 15) {
            System.out.println(name + ",部长已经同意您的请假审批");
        }
    }
}

// 责任链类
public class HandlerChain implements Handler {
    private List handlerList;

    public HandlerChain() {
        this.handlerList = new ArrayList<>();
    }

    public HandlerChain addHandler(Handler handler) {
        handlerList.add(handler);
        return this;
    }


    @Override
    public void handleRequest(String name, int days) {
        for (Handler handler : handlerList) {
            handler.handleRequest(name, days);
        }
    }
}

// 客户类
public class OASystem {
    public static void main(String[] args) {
        // 创建具体处理者
        Handler pm = new PMHandler();
        Handler director = new DirectorHandler();
        Handler minister = new MinisterHandler();
        // 构建责任链
        HandlerChain chain = new HandlerChain()
                .addHandler(pm)
                .addHandler(director)
                .addHandler(minister);

        // 使用责任链
        chain.handleRequest("王二", 10);
    }
}

那么我们使用springboot来使用责任链模式,

使用场景:

用户下单之前得校验工作,按照顺序获取用户订单状态,

通过seqId,检查客户是否重复下单
检查请求参数,是否合法,并且获取客户的银行账户
检查银行账户是否合法,调用银行系统检查银行账户余额是否满足下单金额

订单实体:


/**
 * @Author charles.yao
 * @Description 订单实体类
 * @Date 2023/1/28 14:58
 */
@Data
public class OrderContext {

    /**
     * 请求唯一序列ID
     */
    private String seqId;

    /**
     * 用户ID
     */
    private String userId;

    /**
     * 产品skuId
     */
    private Long skuId;

    /**
     * 下单数量
     */
    private Integer amount;

    /**
     * 用户收货地址ID
     */
    private String userAddressId;
    
}

订单校验抽象接口OrderHandleIntercept


/**
 * @Author charles.yao
 * @Description 订单处理结果类
 * @Date 2023/1/28 15:04
 */
public interface OrderHandleIntercept {
    /**
     * 指定处理顺序
     * @return
     */
    int sort();

    /**
     * 订单处理
     * @param orderContext
     * @return
     */
    OrderAddContext handle(OrderAddContext orderContext);
}

用于重复下单得逻辑验证


/**
 * @Author charles.yao
 * @Description 用于重复下单的逻辑验证
 * @Date 2023/1/28 15:24
 */
@Component
public class RepeatOrderHandleInterceptService implements OrderHandleIntercept{
    @Override
    public int sort() {

        return 1;
    }

    @Override
    public OrderAddContext handle(OrderAddContext orderContext) {
        System.out.println("通过orderId 校验客户是否重复下单");
        return orderContext;
    }
}

用于验证请求参数是否合法


/**
 * @Author charles.yao
 * @Description 用于验证请求参数是否合法
 * @Date 2023/1/28 15:28
 */
@Component
public class ValidOrderHandleInterceptService implements OrderHandleIntercept{
    @Override
    public int sort() {
        return 2;
    }

    @Override
    public OrderAddContext handle(OrderAddContext orderContext) {
        System.out.println("检查请求参数,是否合法,并且获取客户的银行账户");
        return orderContext;
    }
}

用于检查客户账户余额是否充足

/**
 * @Author charles.yao
 * @Description 用于检查客户账户余额是否充足
 * @Date 2023/1/28 15:31
 */
@Component
public class BankOrderHandleInterceptService implements OrderHandleIntercept{
    @Override
    public int sort() {
        return 3;
    }

    @Override
    public OrderAddContext handle(OrderAddContext orderContext) {
        System.out.println("检查银行账户是否合法,调用银行系统检查银行账户余额是否满足下单金额");
        return orderContext;
    }
}

订单验证管理器


/**
 * @Author charles.yao
 * @Description 订单验证管理器
 * @Date 2023/1/28 15:49
 */
@Component
public class OrderHandleChainService implements ApplicationContextAware {
    private List handleList = new ArrayList<>();

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        Map orderHandleInterceptMap = applicationContext.getBeansOfType(OrderHandleIntercept.class);
        handleList = orderHandleInterceptMap.values().stream()
                .sorted(Comparator.comparing(OrderHandleIntercept::sort))
                .collect(Collectors.toList());

    }

    public OrderAddContext execute(OrderAddContext context) {
        for (OrderHandleIntercept orderHandleIntercept : handleList) {
            orderHandleIntercept.handle(context);
        }
        return context;
    }
}

测试类


/**
 * @Author charles.yao
 * @Description 订单测试类
 * @Date 2023/1/28 16:07
 */
@RunWith(SpringRunner.class)
@SpringBootTest
public class CalculatorServiceTest {

    @Autowired
    private OrderHandleChainService orderHandleChainService;

    @Test
    public void test(){
        orderHandleChainService.execute(new OrderAddContext());
    }
}

测试结果

2023-01-28 16:10:01.484  INFO 38155 --- [           main] c.y.d.c.CalculatorServiceTest            : Starting CalculatorServiceTest using Java 1.8.0_212 on localhost with PID 38155 (started by yaoyonghao in /Users/yaoyonghao/Documents/workProject/design-pattern)
2023-01-28 16:10:01.487  INFO 38155 --- [           main] c.y.d.c.CalculatorServiceTest            : No active profile set, falling back to 1 default profile: "default"
2023-01-28 16:10:02.540  INFO 38155 --- [           main] c.y.d.c.CalculatorServiceTest            : Started CalculatorServiceTest in 1.548 seconds (JVM running for 3.081)
通过orderId 校验客户是否重复下单
检查请求参数,是否合法,并且获取客户的银行账户
检查银行账户是否合法,调用银行系统检查银行账户余额是否满足下单金额

当然 也可以通过@Order()注解,来控制执行顺序

你可能感兴趣的:(【设计模式】,java,设计模式,责任链模式,spring,boot)