• 设计模式之责任链模式(场景说明)


    业务场景

    我们来看一个常见的业务场景,下订单。下订单接口,基本的逻辑,一般有参数非空校验、安全校验、黑名单校验、规则拦截等等。很多伙伴会使用异常来实现:

    1. public class Order {
    2. public void checkNullParam(Object param){
    3. //参数非空校验
    4. throw new RuntimeException();
    5. }
    6. public void checkSecurity(){
    7. //安全校验
    8. throw new RuntimeException();
    9. }
    10. public void checkBackList(){
    11. //黑名单校验
    12. throw new RuntimeException();
    13. }
    14. public void checkRule(){
    15. //规则拦截
    16. throw new RuntimeException();
    17. }
    18. public static void main(String[] args) {
    19. Order order = new Order();
    20. try{
    21. order.checkNullParam();
    22. order.checkSecurity ();
    23. order.checkBackList();
    24. order.checkRule();
    25. System.out.println("order success");
    26. }catch (RuntimeException e){
    27. System.out.println("order fail");
    28. }
    29. }
    30. }

    这段代码使用了异常来做逻辑条件判断,如果后续逻辑越来越复杂的话,会出现一些问题:如异常只能返回异常信息,不能返回更多的字段,这时候需要自定义异常类

    并且,阿里开发手册规定:禁止用异常做逻辑判断

    【强制】 异常不要用来做流程控制,条件控制。 说明:异常设计的初衷是解决程序运行中的各种意外情况,且异常的处理效率比条件判断方式要低很多。

    如何优化这段代码呢?可以考虑责任链模式

    责任链模式定义 

    当你想要让一个以上的对象有机会能够处理某个请求的时候,就使用责任链模式

    责任链模式为请求创建了一个接收者对象的链。执行链上有多个对象节点,每个对象节点都有机会(条件匹配)处理请求事务,如果某个对象节点处理完了,就可以根据实际业务需求传递给下一个节点继续处理或者返回处理完毕。这种模式将根据请求的类型,对请求的发送者和接收者进行解耦。

            责任链模式实际上是一种处理请求的模式,它让多个处理器(对象节点)都有机会处理该请求,直到其中某个处理成功为止。责任链模式把多个处理器串成链,然后让请求在链上传递 :

    责任链模式使用 

    责任链模式怎么使用呢?

    1. 一个接口或者抽象类
    2. 每个对象差异化处理
    3. 对象链(数组)初始化(连起来)

    举例如下

    1.一个接口或者抽象类

    这个接口或者抽象类,需要:

    • 有一个指向责任下一个对象的属性
    • 一个设置下一个对象的set方法
    • 给子类对象差异化实现的方法(如以下代码的doFilter方法)
    1. public abstract class AbstractHandler {
    2. //责任链中的下一个对象
    3. private AbstractHandler nextHandler;
    4. /**
    5. * 责任链的下一个对象
    6. */
    7. public void setNextHandler(AbstractHandler nextHandler){
    8. this.nextHandler = nextHandler;
    9. }
    10. /**
    11. * 具体参数拦截逻辑,给子类去实现
    12. */
    13. public void filter(Request request, Response response) { //通用方法 递归调用
    14. doFilter(request, response);
    15. if (getNextHandler() != null) {
    16. getNextHandler().filter(request, response);
    17. }
    18. }
    19. public AbstractHandler getNextHandler() {
    20. return nextHandler;
    21. }
    22. abstract void doFilter(Request filterRequest, Response response); //子类去实现具体的逻辑
    23. }

    2.每个对象差异化处理

            责任链上,每个对象的差异化处理,如本节的业务场景,就有参数校验对象、安全校验对象、黑名单校验对象、规则拦截对象。

    1. /**
    2. * 参数校验对象
    3. **/
    4. @Component
    5. @Order(1) //顺序排第1,最先校验
    6. public class CheckParamFilterObject extends AbstractHandler {
    7. @Override
    8. public void doFilter(Request request, Response response) {
    9. System.out.println("非空参数检查");
    10. }
    11. }
    12. /**
    13. * 安全校验对象
    14. */
    15. @Component
    16. @Order(2) //校验顺序排第2
    17. public class CheckSecurityFilterObject extends AbstractHandler {
    18. @Override
    19. public void doFilter(Request request, Response response) {
    20. //invoke Security check
    21. System.out.println("安全调用校验");
    22. }
    23. }
    24. /**
    25. * 黑名单校验对象
    26. */
    27. @Component
    28. @Order(3) //校验顺序排第3
    29. public class CheckBlackFilterObject extends AbstractHandler {
    30. @Override
    31. public void doFilter(Request request, Response response) {
    32. //invoke black list check
    33. System.out.println("校验黑名单");
    34. }
    35. }
    36. /**
    37. * 规则拦截对象
    38. */
    39. @Component
    40. @Order(4) //校验顺序排第4
    41. public class CheckRuleFilterObject extends AbstractHandler {
    42. @Override
    43. public void doFilter(Request request, Response response) {
    44. //check rule
    45. System.out.println("check rule");
    46. }
    47. }

    3.对象链连起来(初始化)&& 使用

    1. @Component("ChainPatternDemo")
    2. public class ChainPatternDemo {
    3. //自动注入各个责任链的对象
    4. @Autowired
    5. private List<AbstractHandler> abstractHandleList;
    6. private AbstractHandler abstractHandler;
    7. //spring注入后自动执行,责任链的对象连接起来
    8. @PostConstruct
    9. public void initializeChainFilter(){
    10. for(int i = 0;i<abstractHandleList.size();i++){
    11. if(i == 0){
    12. abstractHandler = abstractHandleList.get(0);
    13. }else{
    14. AbstractHandler currentHander = abstractHandleList.get(i - 1);
    15. AbstractHandler nextHander = abstractHandleList.get(i);
    16. currentHander.setNextHandler(nextHander);
    17. }
    18. }
    19. }
    20. //直接调用这个方法使用
    21. public Response exec(Request request, Response response) {
    22. abstractHandler.filter(request, response);
    23. return response;
    24. }
    25. public AbstractHandler getAbstractHandler() {
    26. return abstractHandler;
    27. }
    28. public void setAbstractHandler(AbstractHandler abstractHandler) {
    29. this.abstractHandler = abstractHandler;
    30. }
    31. }

    4.运行结果如下:

  • 相关阅读:
    CSS的Grid布局与Flex布局
    day5ARM
    并发和并行以及他们的区别
    SharpCrafters PostSharp Crack
    1.3.3系统调用
    前端 折叠面板 折叠展开动画
    那些误导消费者的PoE交换机,你知道多少?
    开学季征文|卷生卷死之新学期大学生自救指南!!!
    Linux远程管理工具
    ActiveMQ Artemis与SpringBoot整合
  • 原文地址:https://blog.csdn.net/CoderTnT/article/details/126709502