职责链模式--如何优雅的实现条件过滤

算是读书笔记吧

极客时间--设计模式之美


什么是职责链模式

Avoid coupling the sender of a request to its receiver by giving more than one object a chance to handle the request. Chain the receiving objects and pass the request along the chain until an object handles it.
将请求的发送和接收解耦,让多个接收对象都有机会处理这个请求。将这些接收对象串成一条链,并沿着这条链传递这个请求,直到链上的某个接收对象能够处理它为止

举一个形象的例子,每一层都会过滤掉不同的杂质

对应到代码中,可以看做是在发现某条信息中含有违规信息,就终止当条信息继续传递。

而职责链,就是讲这一层一层的筛选,交给一个一个处理器对象进行处理。


职责链模式如何实现

如果不使用职责链模式

正常情况下,我们会这样设计


public class SensitiveWordFilter {
  // return true if content doesn't contain sensitive words.
  public boolean filter(Content content) {
    if (!filterSexyWord(content)) {
      return false;
    }

    if (!filterAdsWord(content)) {
      return false;
    }

    if (!filterPoliticalWord(content)) {
      return false;
    }

    return true;
  }

  private boolean filterSexyWord(Content content) {
    //....
  }

  private boolean filterAdsWord(Content content) {
    //...
  }

  private boolean filterPoliticalWord(Content content) {
    //...
  }
}

其实很多时候我们都是这样做的,因为这些需求经常会变化。
但是如果要设计一个稳定的框架,我们当然不希望所有逻辑都耦合在这一个方法,甚至文件里。
业务方想要更改一个判断,要修改框架类。这明显违背了开闭原则。

用链表方式实现职责链

通过当前处理器对象调用next,来实现链式调用

每个处理器就是一个节点

public abstract class Handler {
  protected Handler nextHandler = null;

  public void setSuccessor(Handler nextHandler) {
    this.nextHandler = nextHandler;
  }

  public abstract void handle();
}

public class HandlerA extends Handler {
  @Override
  public boolean handle() {
    boolean handled = false;
    //...
    if (!handled && nextHandler != null) {
      nextHandler.handle();
    }
  }
}

对外使用时,总链对象通过激活头结点,开始处理

public class HandlerChain {
  private Handler head = null;
  private Handler tail = null;

  public void addHandler(Handler handler) {
    handler.setSuccessor(null);

    if (head == null) {
      head = handler;
      tail = handler;
      return;
    }

    tail.setSuccessor(handler);
    tail = handler;
  }

  public void handle() {
    if (head != null) {
      head.handle();
    }
  }
}

// 使用举例
public class Application {
  public static void main(String[] args) {
    HandlerChain chain = new HandlerChain();
    chain.addHandler(new HandlerA());
    chain.addHandler(new HandlerB());
    chain.handle();
  }
}

当然,也可以通过在模板方法里调用next,简化编码流程

public abstract class Handler {
  protected Handler nextHandler = null;

  public void setSuccessor(Handler nextHandler) {
    this.nextHandler = nextHandler;
  }

  public final void handle() {
    doHandle();
    if (successor != null) {
      nextHandler.handle();
    }
  }

  protected abstract void doHandle();
}

public class HandlerA extends Handler {
  @Override
  protected void doHandle() {
    //...
  }
}

用数组方式实现职责链

将处理器对象存储在主链的数组容器中,由主链对象依次调用节点

public class SensitiveWordFilterChain {
  private List<SensitiveWordFilter> filters = new ArrayList<>();

  public void addFilter(SensitiveWordFilter filter) {
    this.filters.add(filter);
  }

  // return true if content doesn't contain sensitive words.
  public boolean filter(Content content) {
    for (SensitiveWordFilter filter : filters) {
      if (!filter.doFilter(content)) {
        return false;
      }
    }
    return true;
  }
}

职责链模式的变体

经典的职责链模式

一旦某个处理器能处理这个请求,就不会继续将请求传递给后续的处理器了

职责链模式的变体

请求不会中途终止传递,而是会被所有的处理器都处理一遍。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章