责任链模式是一种行为设计模式,允许你将请求沿着处理链发送,然后处理者都可对其进行处理,完成后可以再将其传递给下一个处理者。
实际应用:
使用场景:
以请假审批系统为例,组长 → 总监→ 部长形成了一条链
职员提交请假申请后,请求会沿着这条链传递,直到有对象可以处理它。
一个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,我们会发现一系列问题:如果对具体处理者得增加、减少或者调整顺序,都涉及整个责任链得调整 重构,反而增加没必要得工作量,我们对上边写法进行改进,改进如下,
// 抽象处理者
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()注解,来控制执行顺序