大話設計模式之—責任鏈模式

  • 2019 年 12 月 16 日
  • 筆記

責任鏈模式,又稱職責鏈模式,Chain Of Responsibility,使多個對象都有機會處理請求,從而避免請求的發送者和接收者之間的耦合關係,將這個對象連成一條鏈,並沿著這條鏈傳遞該請求,直到有一個對象處理它為止。

根據程式碼來體驗,模仿前端消息傳遞過濾。

package com.kk;  /**   * @author zhaokk   * @create 2019-12-08-10:06   */  public class ChainOfResponsibility {      public static void main(String[] args) {          Msg msg = new Msg();          //消息接收          msg.setMsg("你好:),<script>,歡迎的來到996icu");          String str=msg.getMsg();          str = str.replace('<', '[');          str= str.replace('>',']');          msg.setMsg(str);          str= str.replaceAll("996icu","955happy");          msg.setMsg(str);          //過濾          System.out.println(msg.getMsg());      }  }    class Msg {      String name;      String msg;        public String getName() {          return name;      }        public void setName(String name) {          this.name = name;      }        public String getMsg() {          return msg;      }        public void setMsg(String msg) {          this.msg = msg;      }        @Override      public String toString() {          return "Msg{" +                  "name='" + name + ''' +                  ", msg='" + msg + ''' +                  '}';      }  }

輸出:

D:ProgramFilesJavaTestjavajdk1.8.0_141binjava.exe "-javaagent:D:ideaIntelliJ IDEA 2019.1.1libidea_rt.jar=51670:D:ideaIntelliJ IDEA 2019.1.1bin" -Dfile.encoding=UTF-8 -classpath D:ProgramFilesJavaTestjavajdk1.8.0_141jrelibcharsets.jar;D:ProgramFilesJavaTestjavajdk1.8.0_141jrelibdeploy.jar;D:ProgramFilesJavaTestjavajdk1.8.0_141jrelibextaccess-bridge-64.jar;D:ProgramFilesJavaTestjavajdk1.8.0_141jrelibextcldrdata.jar;D:ProgramFilesJavaTestjavajdk1.8.0_141jrelibextdnsns.jar;D:ProgramFilesJavaTestjavajdk1.8.0_141jrelibextjaccess.jar;D:ProgramFilesJavaTestjavajdk1.8.0_141jrelibextjfxrt.jar;D:ProgramFilesJavaTestjavajdk1.8.0_141jrelibextlocaledata.jar;D:ProgramFilesJavaTestjavajdk1.8.0_141jrelibextnashorn.jar;D:ProgramFilesJavaTestjavajdk1.8.0_141jrelibextsunec.jar;D:ProgramFilesJavaTestjavajdk1.8.0_141jrelibextsunjce_provider.jar;D:ProgramFilesJavaTestjavajdk1.8.0_141jrelibextsunmscapi.jar;D:ProgramFilesJavaTestjavajdk1.8.0_141jrelibextsunpkcs11.jar;D:ProgramFilesJavaTestjavajdk1.8.0_141jrelibextzipfs.jar;D:ProgramFilesJavaTestjavajdk1.8.0_141jrelibjavaws.jar;D:ProgramFilesJavaTestjavajdk1.8.0_141jrelibjce.jar;D:ProgramFilesJavaTestjavajdk1.8.0_141jrelibjfr.jar;D:ProgramFilesJavaTestjavajdk1.8.0_141jrelibjfxswt.jar;D:ProgramFilesJavaTestjavajdk1.8.0_141jrelibjsse.jar;D:ProgramFilesJavaTestjavajdk1.8.0_141jrelibmanagement-agent.jar;D:ProgramFilesJavaTestjavajdk1.8.0_141jrelibplugin.jar;D:ProgramFilesJavaTestjavajdk1.8.0_141jrelibresources.jar;D:ProgramFilesJavaTestjavajdk1.8.0_141jrelibrt.jar;D:project01targetclasses;C:Users14620.m2repositorycommons-loggingcommons-logging1.1.3commons-logging-1.1.3.jar;C:Users14620.m2repositorylog4jlog4j1.2.17log4j-1.2.17.jar;C:Users14620.m2repositoryorgslf4jslf4j-api1.7.25slf4j-api-1.7.25.jar;C:Users14620.m2repositoryorgslf4jslf4j-log4j121.7.7slf4j-log4j12-1.7.7.jar;C:Users14620.m2repositorychqoslogbacklogback-classic1.1.7logback-classic-1.1.7.jar;C:Users14620.m2repositorychqoslogbacklogback-core1.1.7logback-core-1.1.7.jar;C:Users14620.m2repositorychqoslogbacklogback-access1.1.7logback-access-1.1.7.jar;C:Users14620.m2repositoryorgapachelogginglog4jlog4j-core2.5log4j-core-2.5.jar;C:Users14620.m2repositoryorgapachelogginglog4jlog4j-api2.5log4j-api-2.5.jar;C:Users14620.m2repositoryjunitjunit4.12junit-4.12.jar;C:Users14620.m2repositoryorghamcresthamcrest-core1.3hamcrest-core-1.3.jar com.kk.ChainOfResponsibility  你好:),[script],歡迎的來到955happy    Process finished with exit code 0

這裡的消息指request請求獲取快取中消息,或者用戶輸入消息,當進行消息過濾時,添加一個特殊符號過濾,添加一個敏感詞過濾處理消息。但當增加需求或者改變敏感詞時,需要增加新功能,且耦合較高。

將變化的程式碼邏輯封裝變化

處理資訊的部分是變化的

我們定義一個介面為Filter

package com.kk;  /**   * @author zhaokk   * @create 2019-12-08-10:24   */  public interface Filter {      void dofilter(Msg msg);  }

處理資訊的兩個實現類

package com.kk;    /**   * 特殊符號   * @author zhaokk   * @create 2019-12-08-10:26   */  public class SpecialFilter implements Filter{      public void dofilter(Msg msg) {          String str=msg.getMsg();          str = str.replace('<', '[');          str= str.replace('>',']');          msg.setMsg(str);      }  }
package com.kk;    /**   * 敏感詞   * @author zhaokk   * @create 2019-12-08-10:27   */  public class SensitiveFilter implements Filter {        public void dofilter(Msg msg) {          String str=msg.getMsg();          str= str.replaceAll("996icu","955happy");          msg.setMsg(str);      }  }
public class ChainOfResponsibility {      public static void main(String[] args) {          Msg msg = new Msg();          msg.setMsg("你好:),<script>,歡迎的來到996icu");          new SpecialFilter().dofilter(msg);          new SensitiveFilter().dofilter(msg);         /* String str=msg.getMsg();          str = str.replace('<', '[');          str= str.replace('>',']');          msg.setMsg(str);          str= str.replaceAll("996icu","955happy");          msg.setMsg(str);*/          System.out.println(msg.getMsg());      }  }

輸出:

D:ProgramFilesJavaTestjavajdk1.8.0_141binjava.exe "-javaagent:D:ideaIntelliJ IDEA 2019.1.1libidea_rt.jar=52130:D:ideaIntelliJ IDEA 2019.1.1bin" -Dfile.encoding=UTF-8 -classpath D:ProgramFilesJavaTestjavajdk1.8.0_141jrelibcharsets.jar;D:ProgramFilesJavaTestjavajdk1.8.0_141jrelibdeploy.jar;D:ProgramFilesJavaTestjavajdk1.8.0_141jrelibextaccess-bridge-64.jar;D:ProgramFilesJavaTestjavajdk1.8.0_141jrelibextcldrdata.jar;D:ProgramFilesJavaTestjavajdk1.8.0_141jrelibextdnsns.jar;D:ProgramFilesJavaTestjavajdk1.8.0_141jrelibextjaccess.jar;D:ProgramFilesJavaTestjavajdk1.8.0_141jrelibextjfxrt.jar;D:ProgramFilesJavaTestjavajdk1.8.0_141jrelibextlocaledata.jar;D:ProgramFilesJavaTestjavajdk1.8.0_141jrelibextnashorn.jar;D:ProgramFilesJavaTestjavajdk1.8.0_141jrelibextsunec.jar;D:ProgramFilesJavaTestjavajdk1.8.0_141jrelibextsunjce_provider.jar;D:ProgramFilesJavaTestjavajdk1.8.0_141jrelibextsunmscapi.jar;D:ProgramFilesJavaTestjavajdk1.8.0_141jrelibextsunpkcs11.jar;D:ProgramFilesJavaTestjavajdk1.8.0_141jrelibextzipfs.jar;D:ProgramFilesJavaTestjavajdk1.8.0_141jrelibjavaws.jar;D:ProgramFilesJavaTestjavajdk1.8.0_141jrelibjce.jar;D:ProgramFilesJavaTestjavajdk1.8.0_141jrelibjfr.jar;D:ProgramFilesJavaTestjavajdk1.8.0_141jrelibjfxswt.jar;D:ProgramFilesJavaTestjavajdk1.8.0_141jrelibjsse.jar;D:ProgramFilesJavaTestjavajdk1.8.0_141jrelibmanagement-agent.jar;D:ProgramFilesJavaTestjavajdk1.8.0_141jrelibplugin.jar;D:ProgramFilesJavaTestjavajdk1.8.0_141jrelibresources.jar;D:ProgramFilesJavaTestjavajdk1.8.0_141jrelibrt.jar;D:project01targetclasses;C:Users14620.m2repositorycommons-loggingcommons-logging1.1.3commons-logging-1.1.3.jar;C:Users14620.m2repositorylog4jlog4j1.2.17log4j-1.2.17.jar;C:Users14620.m2repositoryorgslf4jslf4j-api1.7.25slf4j-api-1.7.25.jar;C:Users14620.m2repositoryorgslf4jslf4j-log4j121.7.7slf4j-log4j12-1.7.7.jar;C:Users14620.m2repositorychqoslogbacklogback-classic1.1.7logback-classic-1.1.7.jar;C:Users14620.m2repositorychqoslogbacklogback-core1.1.7logback-core-1.1.7.jar;C:Users14620.m2repositorychqoslogbacklogback-access1.1.7logback-access-1.1.7.jar;C:Users14620.m2repositoryorgapachelogginglog4jlog4j-core2.5log4j-core-2.5.jar;C:Users14620.m2repositoryorgapachelogginglog4jlog4j-api2.5log4j-api-2.5.jar;C:Users14620.m2repositoryjunitjunit4.12junit-4.12.jar;C:Users14620.m2repositoryorghamcresthamcrest-core1.3hamcrest-core-1.3.jar com.kk.ChainOfResponsibility  你好:),[script],歡迎的來到955happySun Dec 08 10:32:19 CST 2019  Process finished with exit code 0

但是此時如果新的業務邏輯進入還需要定義並引入Filter,如果將所有的Filter放入List,foreachList,也可以將多個Filter穿起來,但是新的Filter增加特需要add。且循環過程中,需要所有Filter過濾完才放出.定義一個

FilterChain

ackage com.kk;    import java.util.ArrayList;  import java.util.List;    /**   * @author zhaokk   * @create 2019-12-08-10:40   */  public class FilterChain {      List<Filter> filterList=new ArrayList<Filter>();      private Msg msg;        public void add(Filter filter){          filterList.add(filter);      }      public void  doFilter(Msg msg){          for (Filter filter : filterList) {              filter.dofilter(msg);          }      }  }

處理邏輯

public class ChainOfResponsibility {      public static void main(String[] args) {          Msg msg = new Msg();          msg.setMsg("你好:),<script>,歡迎的來到996icu");          FilterChain fc = new FilterChain();          fc.add(new SpecialFilter());          fc.add(new SensitiveFilter());          fc.doFilter(msg);         /* String str=msg.getMsg();          str = str.replace('<', '[');          str= str.replace('>',']');          msg.setMsg(str);          str= str.replaceAll("996icu","955happy");          msg.setMsg(str);*/          System.out.println(msg.getMsg()+new Date());      }  }

輸出:

D:ProgramFilesJavaTestjavajdk1.8.0_141binjava.exe "-javaagent:D:ideaIntelliJ IDEA 2019.1.1libidea_rt.jar=52490:D:ideaIntelliJ IDEA 2019.1.1bin" -Dfile.encoding=UTF-8 -classpath D:ProgramFilesJavaTestjavajdk1.8.0_141jrelibcharsets.jar;D:ProgramFilesJavaTestjavajdk1.8.0_141jrelibdeploy.jar;D:ProgramFilesJavaTestjavajdk1.8.0_141jrelibextaccess-bridge-64.jar;D:ProgramFilesJavaTestjavajdk1.8.0_141jrelibextcldrdata.jar;D:ProgramFilesJavaTestjavajdk1.8.0_141jrelibextdnsns.jar;D:ProgramFilesJavaTestjavajdk1.8.0_141jrelibextjaccess.jar;D:ProgramFilesJavaTestjavajdk1.8.0_141jrelibextjfxrt.jar;D:ProgramFilesJavaTestjavajdk1.8.0_141jrelibextlocaledata.jar;D:ProgramFilesJavaTestjavajdk1.8.0_141jrelibextnashorn.jar;D:ProgramFilesJavaTestjavajdk1.8.0_141jrelibextsunec.jar;D:ProgramFilesJavaTestjavajdk1.8.0_141jrelibextsunjce_provider.jar;D:ProgramFilesJavaTestjavajdk1.8.0_141jrelibextsunmscapi.jar;D:ProgramFilesJavaTestjavajdk1.8.0_141jrelibextsunpkcs11.jar;D:ProgramFilesJavaTestjavajdk1.8.0_141jrelibextzipfs.jar;D:ProgramFilesJavaTestjavajdk1.8.0_141jrelibjavaws.jar;D:ProgramFilesJavaTestjavajdk1.8.0_141jrelibjce.jar;D:ProgramFilesJavaTestjavajdk1.8.0_141jrelibjfr.jar;D:ProgramFilesJavaTestjavajdk1.8.0_141jrelibjfxswt.jar;D:ProgramFilesJavaTestjavajdk1.8.0_141jrelibjsse.jar;D:ProgramFilesJavaTestjavajdk1.8.0_141jrelibmanagement-agent.jar;D:ProgramFilesJavaTestjavajdk1.8.0_141jrelibplugin.jar;D:ProgramFilesJavaTestjavajdk1.8.0_141jrelibresources.jar;D:ProgramFilesJavaTestjavajdk1.8.0_141jrelibrt.jar;D:project01targetclasses;C:Users14620.m2repositorycommons-loggingcommons-logging1.1.3commons-logging-1.1.3.jar;C:Users14620.m2repositorylog4jlog4j1.2.17log4j-1.2.17.jar;C:Users14620.m2repositoryorgslf4jslf4j-api1.7.25slf4j-api-1.7.25.jar;C:Users14620.m2repositoryorgslf4jslf4j-log4j121.7.7slf4j-log4j12-1.7.7.jar;C:Users14620.m2repositorychqoslogbacklogback-classic1.1.7logback-classic-1.1.7.jar;C:Users14620.m2repositorychqoslogbacklogback-core1.1.7logback-core-1.1.7.jar;C:Users14620.m2repositorychqoslogbacklogback-access1.1.7logback-access-1.1.7.jar;C:Users14620.m2repositoryorgapachelogginglog4jlog4j-core2.5log4j-core-2.5.jar;C:Users14620.m2repositoryorgapachelogginglog4jlog4j-api2.5log4j-api-2.5.jar;C:Users14620.m2repositoryjunitjunit4.12junit-4.12.jar;C:Users14620.m2repositoryorghamcresthamcrest-core1.3hamcrest-core-1.3.jar com.kk.ChainOfResponsibility  你好:),[script],歡迎的來到955happySun Dec 08 10:53:22 CST 2019  Process finished with exit code 0

此時我們再增加一個對消息處理的RedisFilter,

package com.kk;  /**   * @author zhaokk   * @create 2019-12-08-10:58   */  public class RedisFilter implements Filter {      public void doFilter(Msg msg) {          String rediskry="TH"+msg;          rediskry.replace(":)","");          msg.setMsg(rediskry);      }  }

然後讓FilterChain也實現Filter介面

public static void main(String[] args) {          Msg msg = new Msg();          msg.setMsg("你好:),<script>,歡迎的來到996icu");              FilterChain fc = new FilterChain();          fc.add(new SpecialFilter())                  .add(new SensitiveFilter());          FilterChain fc2 = new FilterChain();          fc2.add(new RedisFilter());          fc2.doFilter(msg);          fc.doFilter(msg);          //fc.add(new SensitiveFilter());         /* String str=msg.getMsg();          str = str.replace('<', '[');          str= str.replace('>',']');          msg.setMsg(str);          str= str.replaceAll("996icu","955happy");          msg.setMsg(str);*/          System.out.println(msg.getMsg()+new Date());      }

但是這裡的消息,必須一條責任鏈處理完,另一條責任鏈也要處理

將一個鏈條看做是Filter加到FilterChain鏈中

fc.add(fc2);

在某一個filter中決定是否繼續往下處理

將Filter返回boolean

public interface Filter {      Boolean doFilter(Msg msg);  }

其他三個過濾器除敏感詞返回false外返回true

public class SensitiveFilter implements Filter {      public Boolean doFilter(Msg msg) {          String str=msg.getMsg();          str= str.replaceAll("996icu","955happy");          msg.setMsg(str);          return false;      }  }

在filterChain中

public Boolean doFilter(Msg msg) {          for (Filter filter : filterList) {              if (!filter.doFilter(msg)) {                  return false;              }          }          return true;      }

此時在三個責任鏈中第二個是返回false,第三個是不予執行的,RedisFilter效果不被執行

D:ProgramFilesJavaTestjavajdk1.8.0_141binjava.exe "-javaagent:D:ideaIntelliJ IDEA 2019.1.1libidea_rt.jar=52994:D:ideaIntelliJ IDEA 2019.1.1bin" -Dfile.encoding=UTF-8 -classpath D:ProgramFilesJavaTestjavajdk1.8.0_141jrelibcharsets.jar;D:ProgramFilesJavaTestjavajdk1.8.0_141jrelibdeploy.jar;D:ProgramFilesJavaTestjavajdk1.8.0_141jrelibextaccess-bridge-64.jar;D:ProgramFilesJavaTestjavajdk1.8.0_141jrelibextcldrdata.jar;D:ProgramFilesJavaTestjavajdk1.8.0_141jrelibextdnsns.jar;D:ProgramFilesJavaTestjavajdk1.8.0_141jrelibextjaccess.jar;D:ProgramFilesJavaTestjavajdk1.8.0_141jrelibextjfxrt.jar;D:ProgramFilesJavaTestjavajdk1.8.0_141jrelibextlocaledata.jar;D:ProgramFilesJavaTestjavajdk1.8.0_141jrelibextnashorn.jar;D:ProgramFilesJavaTestjavajdk1.8.0_141jrelibextsunec.jar;D:ProgramFilesJavaTestjavajdk1.8.0_141jrelibextsunjce_provider.jar;D:ProgramFilesJavaTestjavajdk1.8.0_141jrelibextsunmscapi.jar;D:ProgramFilesJavaTestjavajdk1.8.0_141jrelibextsunpkcs11.jar;D:ProgramFilesJavaTestjavajdk1.8.0_141jrelibextzipfs.jar;D:ProgramFilesJavaTestjavajdk1.8.0_141jrelibjavaws.jar;D:ProgramFilesJavaTestjavajdk1.8.0_141jrelibjce.jar;D:ProgramFilesJavaTestjavajdk1.8.0_141jrelibjfr.jar;D:ProgramFilesJavaTestjavajdk1.8.0_141jrelibjfxswt.jar;D:ProgramFilesJavaTestjavajdk1.8.0_141jrelibjsse.jar;D:ProgramFilesJavaTestjavajdk1.8.0_141jrelibmanagement-agent.jar;D:ProgramFilesJavaTestjavajdk1.8.0_141jrelibplugin.jar;D:ProgramFilesJavaTestjavajdk1.8.0_141jrelibresources.jar;D:ProgramFilesJavaTestjavajdk1.8.0_141jrelibrt.jar;D:project01targetclasses;C:Users14620.m2repositorycommons-loggingcommons-logging1.1.3commons-logging-1.1.3.jar;C:Users14620.m2repositorylog4jlog4j1.2.17log4j-1.2.17.jar;C:Users14620.m2repositoryorgslf4jslf4j-api1.7.25slf4j-api-1.7.25.jar;C:Users14620.m2repositoryorgslf4jslf4j-log4j121.7.7slf4j-log4j12-1.7.7.jar;C:Users14620.m2repositorychqoslogbacklogback-classic1.1.7logback-classic-1.1.7.jar;C:Users14620.m2repositorychqoslogbacklogback-core1.1.7logback-core-1.1.7.jar;C:Users14620.m2repositorychqoslogbacklogback-access1.1.7logback-access-1.1.7.jar;C:Users14620.m2repositoryorgapachelogginglog4jlog4j-core2.5log4j-core-2.5.jar;C:Users14620.m2repositoryorgapachelogginglog4jlog4j-api2.5log4j-api-2.5.jar;C:Users14620.m2repositoryjunitjunit4.12junit-4.12.jar;C:Users14620.m2repositoryorghamcresthamcrest-core1.3hamcrest-core-1.3.jar com.kk.ChainOfResponsibility  你好:),[script],歡迎的來到955happySun Dec 08 11:22:49 CST 2019  Process finished with exit code 0

模擬Severlet API Filter

如何在一條責任鏈處理request與response

response向上返回處理結果

當Filter處理request的時候,讓當前的Filter找到下一個Filter,下一個Filter如此,直到處理完再處理response然後向上返回response至第一層

package com.kk;    /**   * @author zhaokk   * @create 2019-12-08-10:24   */  public interface Filter {      Boolean doFilter(Request request, Response response,FilterChain filterChain);  }

接受者和發送者都沒有對方的明確消息,且鏈中的對象結構也不知道鏈的結構,職責鏈可以簡化對象的相互連接,且易於擴展

package com.kk;    /**   * @author zhaokk   * @create 2019-12-08-10:26   */  public class SpecialFilter implements Filter {      public void doFilter(Request request, Response response, FilterChain filterChain) {          request.setStr(request.getStr().replace('<', '[').replace(">", "]") + "---SpecialFilter()");          filterChain.doFilter(request, response, filterChain);          response.setStr(response.getStr() + "---SpecialFilter()");      }  }
package com.kk;    /**   * @author zhaokk   * @create 2019-12-08-10:58   */  public class RedisFilter implements Filter {      public void doFilter(Request request, Response response,FilterChain filterChain) {          String rediskry="TH"+request.getStr();          request.setStr(rediskry.replace(":)","") + "---SpecialFilter()");          filterChain.doFilter(request, response, filterChain);      }  }

FilterChain

package com.kk;          import java.util.ArrayList;        import java.util.List;  /** * @author zhaokk * @create 2019-12-08-10:40 */public class FilterChain implements Filter {      List<Filter> filterList = new ArrayList<Filter>();    private Msg msg;      public FilterChain add(Filter filter) {        filterList.add(filter);        return this;    }      public void doFilter(Request request, Response response,FilterChain filterChain) {          filterChain.doFilter(request,response,filterChain);    }}
package com.kk;          import java.util.ArrayList;        import java.util.List;  /** * @author zhaokk * @create 2019-12-08-10:40 */public class FilterChain implements Filter {      List<Filter> filterList = new ArrayList<Filter>();    private Msg msg;      public FilterChain add(Filter filter) {        filterList.add(filter);        return this;    }      public void doFilter(Request request, Response response,FilterChain filterChain) {          filterChain.doFilter(request,response,filterChain);    }}

關於設計模式有23種之多,平時看過,只是並不能強化記憶,除了自己做的demo外,很少能第二次用於平時項目,針對性學習,更能加強記憶

為什麼平時看資料會累,因為

第一漫無目的

第二看完得不到應用

第三根本不感興趣

所以有些書,有些影片資料,看一段時間就堅持不下去了

單純通過公眾號學習一門技術是不現實的,只是記錄下當下關注的技術點,並不能夠達到教學的級別,個人也比較隨意,對有些人有幫助,他就覺得你不錯,對別人來說沒幫助,那就很水,但我的目的不在這,我只是享受多年後回來看的那種成就感

平時一有什麼想法我會及時記錄到隨筆中,並以此為樂趣,有時我們難於表達,這些隨筆能記錄並激發你的表達能力