前言html
只有光頭才能變強。文本已收錄至個人GitHub精選文章,歡迎Star:https://github.com/ZhongFuCheng3y/3yjava
最近在看項目代碼的時候發現「責任鏈模式」,因而想花點時間來寫寫什麼是責任鏈模式。git
不知道你們是怎麼學習設計模式的,通常我都是用到的時候,或者接觸到的時候纔會去學。不然感受學完就很容易就忘掉了,不能理解爲何要使用設計模式(由於沒有真實的場景給我去使用)。github
在以前我已經更新說幾篇設計模式的文章了,我以爲寫得「還行」,有興趣的同窗能夠到個人GitHub上,關鍵字搜索「設計模式」,就能找到對應的文章。設計模式
不得不說,我如今負責項目的代碼我經常會感嘆: 這代碼怎麼這麼騷啊!項目裏邊用到了不少的設計模式,在最開始看的時候會很費勁(由於以前沒學),但維護起來是真的方便。
在說責任鏈模式以前,咱們先來聊聊「過濾器」。框架
過濾器相信你們都確定學過了,在最開始學Servlet的時候咱們會學到Filter
。等學到Struts2的時候,咱們會學到Interceptor
。等學到SpringMVC的時候,咱們會學到HandlerInterceptor
。ide
但不管學哪一個框架,咱們發現是最終其實它仍是作Filter
這麼一件事。說白了就是:工具
在個人 GitHub對Filter,HandlerInterceptor,Interceptor都有講到,若是想要複習的同窗不妨進去搜索關鍵字「 過濾器」「 Struts2」「 SpringMVC」
爲何看責任鏈模式要聊「過濾器」呢?後面會講到,不要着急。學習
舉個例子:把咱們的正常請求想象成一堆的雜物,裏邊有米豆,有雞蛋,有敖丙公仔玩具等等一些雜物。ui
如今咱們想要最後獲得的是米豆,雞蛋和敖丙玩具都被過濾掉。因而咱們就能夠搞兩個濾網,把敖丙玩具和雞蛋給過濾掉。
以最快的方式,咱們能夠寫if
來把這個需求給搞掂,下面上代碼。
一個請求,咱們使用Request
對象來表示:
public class Request { // 請求的數據 private String data; public String getData() { return data; } public void setData(String data) { this.data = data; } }
針對請求,咱們確定是有一個接口處理請求的啦,咱們使用Handler
來表示:
public class Handler { public void handlerRequest(Request request) { // 獲得請求的數據 String data = request.getData(); if (data.contains("雞蛋")) { filterEgg(data); } if (data.contains("敖丙工具")) { filterAoBing(data); } // 我到這裏就能拿到米豆了。 } private void filterAoBing(String data) { //doSomething } private void filterEgg(String data) { //doSomething } }
上面的代碼你們不知道熟不熟悉,反正我就很熟悉,不少時候我就是這樣寫代碼的(在現實裏邊不少代碼就是這樣的)。
在某年某月產品過來告訴我,須要新增一種類型想要過濾的「白菜」
在某年某月產品過來告訴我,須要新增一種類型想要過濾的「雞腿」
在某年某月產品過來告訴我,須要新增一種類型想要過濾的「雞頭」
因而咱們的Handler處理就可能「膨脹」起來了,多是這樣?
public class Handler { public void handlerRequest(Request request) { // 獲得請求的數據 String data = request.getData(); if (data.contains("雞蛋")) { filterEgg(data); } if (data.contains("敖丙工具")) { filterAoBing(data); } if (data.contains("白菜")) { filterBaiCai(data); } if (data.contains("雞頭")) { filterJiTou(data); } if (data.contains("雞腿")) { filterJiTui(data); } // 我到這裏就能拿到米豆了。 } private void filterJiTou(String data) { //doSomething } private void filterJiTui(String data) { //doSomething } private void filterAoBing(String data) { //doSomething } private void filterEgg(String data) { //doSomething } }
明顯的是,若是處理的流程改動比較大的話(須要增刪改其中的某個流程),那我每次都須要更改handlerRequest
的代碼,增長/修改/刪除一個if
和一個處理方法。
更加面向對象的方式是這樣的:將每一個處理的方式抽象成一個類,每一個類各司其職。
不管是過濾敖丙仍是過濾雞蛋仍是過濾米豆,作的事都是過濾。咱們就能夠將其抽象成接口。因而咱們就有一個接口,多個實現類。
public interface Filter { // 過濾 void doFilter(String data); } class FilterEgg implements Filter { @Override public void doFilter(String data) { //doSomething } } class FilterAoBing implements Filter { @Override public void doFilter(String data) { //doSomething } } class FilterBaiCai implements Filter { @Override public void doFilter(String data) { //doSomething } } class FilterJiTou implements Filter { @Override public void doFilter(String data) { //doSomething } }
每一個各司其職的Filter都有可能被執行,咱們能夠將其串成一條鏈,抽象一層對外只暴露一個方法來替代if
。因而咱們能夠寫出一個FilterChain
類
public class FilterChain { List<Filter> filters = new ArrayList<>(); public FilterChain() { filters.add(new FilterEgg()); filters.add(new FilterAoBing()); filters.add(new FilterBaiCai()); filters.add(new FilterJiTou()); } public void processData(String data) { for (Filter filter : filters) { filter.doFilter(data); } } }
改造事後,咱們的Handler
就長這個樣子了:
public class Handler { public void handlerRequest(Request request) { // 獲得請求的數據 String data = request.getData(); FilterChain filterChain = new FilterChain(); // 處理數據 filterChain.processData(data); } }
若是我告訴你,這種的處理方式就是責任鏈模式,你會怎麼想?
再來回顧一下,我作了些什麼:
if
和方法
)Chain
鏈起來,暴露一個方法給Handler使用下面我畫了一張對比圖:
是否是很簡單?說到底仍是抽象了一層(將每一個處理抽象爲一個類而已)。
那爲何要這樣幹?若是我要增長一個處理流程,我是得新增一個處理類,而後在鏈上增長相對應的類。操做也的確如此。
這不麻煩嗎?要便捷的話,我還不如直接增長一個if
,一個處理方法來得方便呢。
用責任鏈模式的好處就是分工明確,解耦,容易維護。
if else
耦合性相對較低。Handler
處理類,不會影響到BaseHandler
的代碼責任鏈模式的缺點:
doChain
方法,而裏邊由多個處理類來組成,還得看相應的調用順序)咱們從上面也能夠看到責任鏈模式主要有如下特色:
有這兩個特色我就稱這些代碼運用了責任鏈模式。在翻閱資料或者看書的時候,你可能會看到:「純責任鏈和不純責任鏈」
還有就是將各個具體的Handler串成一條鏈,這裏邊的實現會有各式各樣的:
new
出一個ArrayList,而後在構造方法裏邊代碼手動add到ArrayList的其實沒必要要在乎純和不純的責任鏈模式,咱們學設計模式是爲了學它的思想。
在文章最開頭我就說了咱們之前學過的Filter,其實Filter就是用了責任鏈模式。咱們來簡單看看代碼:
咱們在使用Filter過濾器的時候,要麼在XML上配置<filter>
,要麼在代碼上寫上註解@WebFilter(filterName = "",urlPatterns = "")
這些配置都會在Web容器啓動的時候被讀取,讀完這些配置,會將你寫的Filter過濾器加到FilterChain裏邊:
咱們能夠看到Filter接口下有不少都實現了doFilter
:
JavaWeb的Filter實際用到的也是責任鏈模式。
設計模式自己不是一件很複雜的東西,像門面模式,模板方法模式都很是容易理解。學完了會有一種感受:「啊?就這?」
重要的是學完能不能用到實際的工做中,這是很是難能難得的。咱們寫代碼按照自身的思惟寫if else
是很是簡單的,而設計模式每每須要繞一個圈才能把功能實現。
可是,合理運用設計模式的代碼是很是好維護的。若是你懂設計模式,那代碼會看起來很是清晰。若是你不懂設計模式,你就會感嘆「這代碼是真的騷阿」(這就是我...)。
好好學習,但願有朝一日,別人看到個人代碼,在背後說「這人寫的代碼是真的騷,牛逼阿」。
參考資料:
本已收錄至個人GitHub精選文章,歡迎Star: https://github.com/ZhongFuCheng3y/3y樂於輸出乾貨的Java技術公衆號:Java3y。公衆號內有300多篇原創技術文章、海量視頻資源、精美腦圖,關注便可獲取!
很是感謝人才們能看到這裏,若是這個文章寫得還不錯,以爲「三歪」我有點東西的話 求點贊 求關注️ 求分享👥 求留言💬 對暖男我來講真的 很是有用!!!
創做不易,各位的支持和承認,就是我創做的最大動力,咱們下篇文章見!