第的莫斯科市燒烤模式(1 / 3)

ror) \u003d> { const errorStatus \u003d error.response.status; if (errorStatus \u003d\u003d\u003d 400) { console.log(\u0027你是不是提交了什麼奇怪的東西?\u0027); } if (errorStatus \u003d\u003d\u003d 401) { console.log(\u0027需要先登陸!\u0027); } if (errorStatus \u003d\u003d\u003d 403) { console.log(\u0027是不是想偷摸幹壞事?\u0027); } if (errorStatus \u003d\u003d\u003d 404) { console.log(\u0027這裏什麼也沒有...\u0027); } };

當然實際項目中不可能隻有一行 console,這是為了說明原理的簡化版。

代碼中的 httpErrorHandler 會接收 API 的響應錯誤,並對錯誤的狀態碼做不同的處理,所以代碼中需要很多 if(或者 switch)判斷當前需要要執行什麼,當你要對新的錯誤添加處理代碼時,就必須要到 httpErrorHandler 中修改代碼。

雖然免不了要經常修改代碼,但是這樣做可能會導致幾個問題,下麵根據 SOLID 的 單一職責(Single responsibility)和開放封閉(open/close)這兩個原則來說明:

單一職責(Single responsibility)現在的 httpErrorHandler 其實是策略模式(strategy pattern),httpErrorHandler 用了統一的接口(方法)來處理各種不同的錯誤狀態,在本文的最後會再次解釋策略模式和責任鏈之間的區別。

責任鏈模式(Chain of Responsibility Pattern)

責任鏈的實現原理很簡單,就是把所有方法串起來一個一個執行,並且每個方法都隻做自己要做的事就行了,例如 response400 隻在遇到狀態碼為 400 的時候執行,而 response401 隻處理 401 的錯誤,其他方法也都隻在自己該處理的時候執行。每個人各司其職,就是責任鏈。

接下來開始實現。

增加判斷

根據責任鏈的定義,每個方法都必須要知道當前這件事是不是自己應該處理的,所以要把原本在 httpErrorHandler 實現的 if 判斷分散到每個方法中,變成由內部控製自己的責任:

const response400 \u003d (error) \u003d> { if (error.response.status !\u003d\u003d 400) return; console.log(\u0027你是不是提交了什麼奇怪的東西?\u0027); }; const response401 \u003d (error) \u003d> { if (error.response.status !\u003d\u003d 401) return; console.log(\u0027需要先登陸!\u0027); }; const response403 \u003d (error) \u003d> { if (error.response.status !\u003d\u003d 403) return; console.log(\u0027是不是想偷摸幹壞事?\u0027); }; const response404 \u003d (error) \u003d> { if (error.response.status !\u003d\u003d 404) return; console.log(\u0027這裏什麼也沒有...\u0027); }; const httpErrorHandler \u003d (error) \u003d> { response400(error); response401(error); response403(error); response404(error); };

把判斷的邏輯放到各自的方法中之後,httpErrorHandler 的代碼就精簡了很多,也去除了所有在 httpErrorHandler 中的邏輯,現在httpErrorHandler 隻需要按照順序執行 response400 到 response404 就行了,反正該執行就執行,不該執行的也隻是直接 return 而已。

實現真正的責任鏈

雖然隻要重構到上一步,所有被分拆的錯誤處理方法都會自行判斷當前是不是自己該做的,但是如果你的代碼就這樣了,那麼將來看到 httpErrorHandler 的其他人隻會說:

這是什麼神仙代碼?API 一遇到錯誤就執行所有錯誤處理?

因為他們不知道在每個處理方法裏麵還有判斷,也許過一段時間之後你自己也會忘了這事,因為現在的 httpErrorHandler 看起來就隻是從 response400 到 response404,即使我們知道功能正確,但完全看不出是用了責任鏈。

那到底怎樣才能看起來像是個鏈呢?其實你可以直接用一個數字記錄所有要被執行的錯誤處理方法,並通過命名告訴將來看到這段代碼的人這裏是責任鏈:

const httpErrorHandler \u003d (error) \u003d> { const errorHandlerChain \u003d [ response400, response401, response403, response404 ]; errorHandlerChain.forEach((errorHandler) \u003d> { errorHandler(error); }); };

優化執行

這樣一來責任鏈的目的就有達到了,如果像上麵代碼中用 forEach 處理的話,那當遇到 400 錯誤時,實際上是不需要執行後麵的 response401 到 response404 的。

所以還要在每個錯誤處理的方法中加上一些邏輯,讓每個方法可以判斷,如果是遇到自己處理不了的事情,就丟出一個指定的字符串或布爾值,接收到之後就再接著執行下一個方法,但如果該方法可以處理,則在處理完畢之後直接結束,不需要再繼續把整個鏈跑完。

const response400 \u003d (error) \u003d> { if (error.response.status !\u003d\u003d 400) return \u0027next\u0027; console.log(\u0027你是不是提交了什麼奇怪的東西?\u0027); }; const response401 \u003d (error) \u003d> { if (error.response.status !\u003d\u003d 401) return \u0027next\u0027; console.log(\u0027需要先登陸!\u0027); }; const response403 \u003d (error) \u003d> { if (error.response.status !\u003d\u003d 403) return \u0027next\u0027;; console.log(\u0027是不是想偷摸幹壞事?\u0027); }; const response404 \u003d (error) \u003d> { if (error.response.status !\u003d\u003d 404) return \u0027next\u0027;; console.log(\u0027這裏什麼都沒有...\u0027); };

如果鏈中某個節點執行結果為 next,則讓下後麵的方法繼續處理:

const httpErrorHandler \u003d (error) \u003d> { const errorHandlerChain \u003d [ response400, response401, response403, response404 ]; for(errorHandler of errorHandlerChain) { const result \u003d errorHandler(error); if (result !\u003d\u003d \u0027next\u0027) break; }; };