前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >设计模式之责任链模式

设计模式之责任链模式

作者头像
Dylan Liu
发布2019-11-27 10:59:49
5570
发布2019-11-27 10:59:49
举报
文章被收录于专栏:dylanliudylanliu

简介

责任链模式(Chain of Responsibility Pattern)属于设计模式的行为型模式。责任链模式与多米诺骨牌有点类似,请求在链中从前向后传递,一直到最后一个。当然责任链的处理可以复杂的多。

定义

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

可以看到在标准的责任链中,请求是只由一个对象来处理的。不过我们不用拘泥于这个定义,责任链的主要目的是将请求处理的各个对象解耦出来,至于在链中传递时有多少个对象处理了请求,其实并不重要。

角色

从定义中可以看出,责任链模式包含的角色有有发送者,请求处理接口,具体请求处理实现及将实现连接起来的链。

发送者:产生请求对象,发起对链的调用 请求处理接口: 定义处理的标准接口,所有的具体请求处理实现都需要实现这个接口,链只需要依赖接口即可 具体请求处理实现:对请求进行处理,并决定是否继续向后传递请求 链:将所有的请求组装到一起,变成一个有序的处理链条

责任链模式可简单可复杂,一般来说接口和实现是必须的,链对象可以简单变为一个 List,处理顺序也可以简化为 for 循环与发送者耦合到一起。如果处理比较复杂,像 Servlet Filter,网络请求库的Handler等框架则会有一个链对象,而且链中的下一级调用与否是由 handler 来决定的。

模式说明

在日志打印框架中,我们会定义很多日志级别,不同级别的日志logger我们可以使用责任链模式来串联起来。

代码语言:javascript
复制
//日志级别
public enum LogLevel {
    DEBUG, INFO, WARN, ERROR
}

@FunctionalInterface
public interface Logger {
    abstract void log(String msg, LogLevel level);
    
    //utitlity methods
    default void debug(String msg) {
        log(msg, LogLevel.DEBUG);
    }
    
    default void info(String msg) {
        log(msg, LogLevel.INFO);
    }
    
    default void warn(String msg) {
        log(msg, LogLevel.WARN);
    }
    
    default void error(String msg) {
        log(msg, LogLevel.ERROR);
    }
    
    default Logger appendNext(Logger logger) {
        return (msg, level) -> {
            //call self
            log(msg, level);
            //call next Logger
            logger.log(msg, level);
        }
    }
}

public class LoggerFactory {
    public static Logger consoleLogger(LogLevel[] levels) {
        EnumSet<LogLevel> set = EnumSet.copyOf(Arrays.asList(levels));
        return (msg, level) {
            if (set.contains(level)) {
                System.out.println("log to console: " + msg);
            }
        }
    }
    
    public static Logger fileLogger(LogLevel[] levels) {
        EnumSet<LogLevel> set = EnumSet.copyOf(Arrays.asList(levels));
        return (msg, level) {
            if (set.contains(level)) {
                System.out.println("log to file: " + msg);
            }
        }
    }
    
    public static Logger emailLogger(LogLevel[] levels) {
        EnumSet<LogLevel> set = EnumSet.copyOf(Arrays.asList(levels));
        return (msg, level) {
            if (set.contains(level)) {
                System.out.println("log to email: " + msg);
            }
        }
    }
}


/**
 * Logger user
 */
public class Application {
    public static void main(String[] args) {
        Logger logger = LoggerFactory.consoleLogger(LoggerLevel.values()
                                .appendNext(LoggerFactory.fileLogger(new LogLevel[]{LogLevel.INFO, LogLevel.WARN, LogLevel.ERROR})
                                .appendNext(LoggerFactory.emailLogger(new LogLevel[]{LogLevel.ERROR});
                                
        logger.debug("log will only show in console logger");
        logger.info("log will be printed in console and file loggers");
        logger.warn("log will show in console and file loggers");
        logger.error("log will show in console, file and email loggers");
    }
}

使用场景

  • 一个请求需要被多次处理,将处理过程解耦的场景(Logger)
  • 有多级处理,由前面的处理结果来决定后续逻辑是否继续(Filter,Handler)
  • 现实场景中的级联处理情况,像在公司中审批从下往上审批(workflow)
  • 责任链是一个从前到后的处理流程,这与我们平常学习到的面向过程变成是一致的,因此函数的处理流程都可以抽象成责任链模式

优点

  • 处理解耦,众多的处理逻辑不是集中在一起使用 if..ele 来判断,而是由各自的类来决定如何处理
  • 符合开闭原则,增加处理逻辑不用修改其他的类,只需要增加到处理链条上
  • 符合最少知识原则。没有一个类负责所有的判断,每个处理类只负责自己的相关部分即可

缺点

  • 处理逻辑分散在很多类中,造成调试困难
  • 处理逻辑在不同的类中有时很改变请求对象,这就必须要小心维护链中处理对象的顺序
  • 请求处理分散,不能保证请求一定被处理
  • 链的构造要小心,可能造成死循环
  • 类过多,增加了函数调用,会造成性能损失

责任链的变种

纯的责任链一般要求请求只会被一个处理对象处理,也就是说链中的对象要么处理请求,要么调用下一个对象。要求太严格,只起到了解耦逻辑的作用。

日常使用的一般都是不纯的责任链(期待以后这变成责任链的正确定义),每个处理对象处理一部分逻辑,连起来变成整个逻辑。而且每个对象也不一定要传递给下一级,而是终止请求处理(拦截器Filter,Interceptor,Handler都是这种形式)。上面的日志处理例子也是不纯的责任链。

责任链使用中一般都是前后相连的一根链条,这是为了简单。链也可以变成树或有向图,也就是每个处理对象可以由多个后继,增加处理的灵活性(没见过)。

最佳实践

  • 链一般是由客户端或其他方法创建的,可以与设计模式的创建型模式相结合
  • 上面我们使用了接口,也可以使用抽象类来定义模版方法,决定是调用下一级还是使用当前处理。子类只需实现判断条件和处理逻辑即可,链交由父类模板
  • 责任链模式是一种工作流思想,可以认为是一种语言级别的工作流实现。如果流程太过复杂,责任链模式是有短板的,这时可以考虑引入工作流引擎。
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 定义
  • 角色
  • 模式说明
  • 使用场景
  • 优点
  • 缺点
  • 责任链的变种
  • 最佳实践
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档