【设计模式】责任链模式

一、前言

  责任链模式很多框架都有用到,其中一个经典场景就是Tomcat对HTTP请求的处理。
  Tomcat处理HTTP请求时就会处理请求头和请求体两部分,当然,Tomcat的真正实现会将HTTP请求切分成更细的部分进行处理。如果请求各部分的逻辑都在一个类中实现,这个类会非常臃肿。如果请求通过增加新字段完成升级,则接受者需要添加处理新字段的处理逻辑,这就需要修改该类的代码,不符合“开放-封闭”原则。
  责任链模式就可以很好地处理上述问题,将上述完整的、臃肿的接受者的实现逻辑拆分到多个只包含部分逻辑的、功能单一的Handler处理类中,开发人员可以根据业务需求将多个Handler对象组合成一条责任链,实现请求的处理。在一条责任链中,每个Handler对象都包括对下一个Handler对象的引用,一个Handler对象处理完请求消息(或不能处理该请求)时,会把请求传给下一个Handler对象继续处理,以此类推,直至整条责任链结束。
责任链模式的类图如下:

 

enter description here
enter description here

优点:
1.弱化了发出请求的人和处理请求的人之间的关系
2.可以动态的改变责任链,删除或者添加或者改变顺序。
3.让各个处理者专注于实现自己的职责
缺点
1.如果构造的责任链变成了环形结构,进行代码调试和定位问题比较困难
2.推卸责任也可能导致处理延迟

 

二、初始版实现

需求是给定一个日志级别,不高于这个日志级别的日志记录器都会打印自己的日志信息。
第一步:创建抽象日志处理器
AbstractLogger

public abstract class AbstractLogger {

  public static int INFO = 1;
  public static int DEBUG = 2;
  public static int ERROR = 3;

  protected int level;

  // 责任链中的下一个元素
  protected AbstractLogger nextLogger;

  public void setNextLogger(AbstractLogger nextLogger) {
    this.nextLogger = nextLogger;
  }

  public void logMessage(int level, String message) {
    if (this.level <= level) {
      write(message);
    }
    if (nextLogger != null) {
      nextLogger.logMessage(level, message);
    }
  }

  abstract protected void write(String message);
}

第二步:具体日志处理器
ConsoleLogger

public class ConsoleLogger extends AbstractLogger {

  public ConsoleLogger(int level){
    this.level = level;
  }

  @Override
  protected void write(String message) {
    System.out.println("Standard Console::Logger: " + message);
  }
}

ErrorLogger

public class ErrorLogger extends AbstractLogger {

  public ErrorLogger(int level){
    this.level = level;
  }

  @Override
  protected void write(String message) {
    System.out.println("Error Console::Logger: " + message);
  }
}

FileLogger

public class FileLogger extends AbstractLogger {

  public FileLogger(int level) {
    this.level = level;
  }

  @Override
  protected void write(String message) {
    System.out.println("File::Logger: " + message);
  }
}

ChainPatternDemo

public class ChainPatternDemo {

  public static void main(String[] args) {
    AbstractLogger loggerChain = getChainOfLoggers();
    loggerChain.logMessage(AbstractLogger.INFO,
        "This is an information.");

    loggerChain.logMessage(AbstractLogger.DEBUG,
        "This is an debug level information.");

    loggerChain.logMessage(AbstractLogger.ERROR,
        "This is an error information.");

  }

  private static AbstractLogger getChainOfLoggers(){
    ErrorLogger errorLogger = new ErrorLogger(AbstractLogger.ERROR);
    FileLogger fileLogger = new FileLogger(AbstractLogger.DEBUG);
    ConsoleLogger consoleLogger = new ConsoleLogger(AbstractLogger.INFO);

    errorLogger.setNextLogger(fileLogger);
    fileLogger.setNextLogger(consoleLogger);
    return errorLogger;
  }

  

}

运行Main方法,测试结果如图。

 

enter description here
enter description here

 

三、升级版实现

上面的方式实现了功能,但是不够优雅,还需要手动调用setXX方法来设置引用,于是有了下面升级版的实现。
类图如下:

 

enter description here
enter description here

FilterChain

 

public class FilterChain extends AbstractLoggerFilter {

  private int pos;

  private List<AbstractLoggerFilter> loggerFilterList;


  public void addFilter(AbstractLoggerFilter loggerFilter) {
    if (loggerFilterList == null) {
      loggerFilterList = new ArrayList<>();
    }
    loggerFilterList.add(loggerFilter);
  }

  @Override
  void doFilter(int level, FilterChain filterChain) {
    if (pos == loggerFilterList.size()) {
      return;
    }
    filterChain.loggerFilterList.get(pos++).doFilter(level, filterChain);
  }


}

这个过滤器链有两个属性,pos用于表示当前过滤器在过滤器集合中的角标,loggerFilterList是过滤器的集合。
doFilter() 方法先判断是否全部处理完了,如果不是就交给下个处理器去处理,递归调用。

AbstractLoggerFilter

public abstract class AbstractLoggerFilter {

  abstract void doFilter(int level,FilterChain filterChain);
}

ConsoleLoggerFilter

public class ConsoleLoggerFilter extends AbstractLoggerFilter {

  private LoggerInfo loggerInfo;

  public ConsoleLoggerFilter(LoggerInfo loggerInfo){
    this.loggerInfo = loggerInfo;
  }

  @Override
  void doFilter(int level, FilterChain filterChain) {
    if (loggerInfo.getLevel() <= level){
      System.out.println("Standard Console::Logger: " + loggerInfo.getMessage());
    }
    filterChain.doFilter(level,filterChain);
  }
}

ErrorLoggerFilter

public class ErrorLoggerFilter extends AbstractLoggerFilter {

  private LoggerInfo loggerInfo;

  public ErrorLoggerFilter(LoggerInfo loggerInfo){
    this.loggerInfo = loggerInfo;
  }

  @Override
  void doFilter(int level, FilterChain filterChain) {
    if (loggerInfo.getLevel() <= level){
      System.out.println("Error Console::Logger: " + loggerInfo.getMessage());
    }
    filterChain.doFilter(level,filterChain);
  }
}

FileLoggerFilter

public class FileLoggerFilter extends AbstractLoggerFilter {

  private LoggerInfo loggerInfo;

  public FileLoggerFilter(LoggerInfo loggerInfo){
    this.loggerInfo = loggerInfo;
  }

  @Override
  void doFilter(int level, FilterChain filterChain) {
    if (loggerInfo.getLevel() <= level){
      System.out.println("File::Logger: " + loggerInfo.getMessage());
    }
    filterChain.doFilter(level,filterChain);
  }
}

实体类LoggerInfo

public class LoggerInfo {

  private int level;

  private String message;

  public LoggerInfo(int level, String message) {
    this.level = level;
    this.message = message;
  }

//省略get/set方法
}

客户端LoggerFilterDemo

public class LoggerFilterDemo {

  public static int INFO = 1;
  public static int DEBUG = 2;
  public static int ERROR = 3;

  public static void main(String[] args) {
    ConsoleLoggerFilter consoleLoggerFilter = new ConsoleLoggerFilter(
        new LoggerInfo(INFO, "This is an information."));
    ErrorLoggerFilter errorLoggerFilter = new ErrorLoggerFilter(
        new LoggerInfo(ERROR, "This is an error information."));
    FileLoggerFilter fileLoggerFilter = new FileLoggerFilter(
        new LoggerInfo(DEBUG, "This is an debug level information."));
    FilterChain filterChain = new FilterChain();
    filterChain.addFilter(consoleLoggerFilter);
    filterChain.addFilter(errorLoggerFilter);
    filterChain.addFilter(fileLoggerFilter);

    filterChain.doFilter(ERROR, filterChain);
  }

}

如果以后还需要添加新类型的Logger,只需要new出来添加到FilterChain中就可以了。
运行测试类,可以看到所有类型的Logger都打印了日志。

Standard Console::Logger: This is an information.
Error Console::Logger: This is an error information.
File::Logger: This is an debug level information.

代码地址。

posted @ 2019-09-07 20:28  烟味i  阅读(484)  评论(0编辑  收藏  举报