zoukankan      html  css  js  c++  java
  • 设计模式之责任链模式

    前言

    责任链模式使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。

    request -> 处理器1 -> 处理器2 -> 处理器3 -> 返回结果

    比如财务审批系统,组长可以审批一千元,部门经理审批一千到一万元的,ceo任意金额的额度。每个审核者只关心自己责任范围内的请求,并且处理它。对于超出自己责任范围的,扔给下一个审核者处理,这样,将来继续添加审核者的时候,不用改动现有逻辑。

    代码实现

    请求对象:

    @Data
    @AllArgsConstructor
    public class User {
        private String name;
        private BigDecimal money;
    }
    

    抽象的处理器:

    public interface Handler {
        Boolean process(User user);
    }
    

    具体处理器 First,Second,Third

    public class FirstManagerHandler implements Handler {
        @Override
        public Boolean process(User user) {
            // 超过一千元 处理不了
            if (user.getMoney().compareTo(BigDecimal.valueOf(1000)) > 0) {
                return null;
            }
            return true;
        }
    }
    
    public class SecondManagerHandler implements Handler {
        @Override
        public Boolean process(User user) {
            // 超过一万元 处理不了
            if (user.getMoney().compareTo(BigDecimal.valueOf(10000)) > 0) {
                return null;
            }
            return true;
        }
    }
    
    public class ThirdManagerHandler implements Handler {
        @Override
        public Boolean process(User user) {
            // 永远可以审批
            return true;
        }
    }
    

    处理链逻辑:

    public class HandlerChain {
    
        private List<Handler> handlers = new ArrayList<>();
    
        public void addHandler(Handler handler) {
            handlers.add(handler);
        }
    
        public boolean process(User user) {
            for (Handler handler : handlers) {
                Boolean isAccess = handler.process(user);
                if (isAccess != null) {
                    return isAccess;
                }
            }
            throw new RuntimeException("没有人能处理");
        }
    }
    

    测试类:

    public class HandlerChainTest {
    
        public static void main(String[] args) {
            // 构建处理链
            HandlerChain chain = new HandlerChain();
            chain.addHandler(new FirstManagerHandler());
            chain.addHandler(new SecondManagerHandler());
            chain.addHandler(new ThirdManagerHandler());
    
            chain.process(new User("xiaoming", BigDecimal.valueOf(1000.1)));
        }
    }
    

    有些责任链的实现方式是通过某个Handler手动调用下一个Handler来传递Request

    public class HandlerV2 implements Handler {
    
        private Handler next;
    
        @Override
        public Boolean process(User user) {
            if (user.getMoney().compareTo(BigDecimal.valueOf(1000)) > 0) {
                return true;
            } else {
                return next.process(user);
            }
        }
    }
    

    还有一些责任链模式,每个Handler都有机会处理Request,通常这种责任链被称为拦截器(Interceptor)或者过滤器(Filter),它的目的不是找到某个Handler处理掉Request,而是每个Handler都做一些工作

    例如,JavaEE的Servlet规范定义的Filter就是一种责任链模式,它不但允许每个Filter都有机会处理请求,还允许每个Filter决定是否将请求“放行”给下一个Filter(接下来说的管道模式)

    public class AuditFilter implements Filter {
        public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {
            log(req);
            if (check(req)) {
                // 放行:
                chain.doFilter(req, resp);
            } else {
                // 拒绝:
                sendError(resp);
            }
        }
    }
    

    这种模式不但允许一个Filter自行决定处理ServletRequest和ServletResponse,还可以“伪造”ServletRequest和ServletResponse以便让下一个Filter处理,能实现非常复杂的功能。

    管道模式

    管道模式(Pipeline Pattern) 是责任链模式(Chain of Responsibility Pattern)的常用变体之一。在管道模式中,管道扮演着流水线的角色,将数据传递到一个加工处理序列中,数据在每个步骤中被加工处理后,传递到下一个步骤进行加工处理,直到全部步骤处理完毕。

    纯的责任链模式在链上只会有一个处理器用于处理数据,而管道模式上多个处理器都会处理数据。

    何时使用管道模式

    任务代码较为复杂,需要拆分为多个子步骤时,尤其是后续可能在任意位置添加新的子步骤、删除旧的子步骤、交换子步骤顺序,可以考虑使用管道模式。

    源码应用中可参考 Netty中的责任链 Logback 中的责任链

    References
  • 相关阅读:
    递增一个指针
    ubuntu 系统 sudo apt-get update遇到问题sub-process returned an error code
    熟悉HDFS过程中遇到的问题
    大二暑假第八周进度报告
    大二暑假第七周进度报告
    oracle“ORA-00904”错误:标识符无效
    大学暑假第六周进度报告
    大二暑假第五周进度报告
    使用Navicat for Oracle新建表空间、用户及权限赋予
    大学暑假第四周进度报告
  • 原文地址:https://www.cnblogs.com/wei57960/p/14310544.html
Copyright © 2011-2022 走看看