職責鏈模式--如何優雅的實現條件過濾

算是讀書筆記吧

極客時間--設計模式之美


什麼是職責鏈模式

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;
  }
}

職責鏈模式的變體

經典的職責鏈模式

一旦某個處理器能處理這個請求,就不會繼續將請求傳遞給後續的處理器了

職責鏈模式的變體

請求不會中途終止傳遞,而是會被所有的處理器都處理一遍。

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