Chain of Responsibility(職責鏈模式)屬於行爲型模式。行爲型模式不只描述對象或類的模式,還描述它們之間的通訊模式,好比對操做的處理應該如何傳遞等等。前端
意圖:使多個對象都有機會處理請求,從而避免請求的發送者和接收者之間的耦合關係。將這些對象連成一條鏈,並沿着這條鏈傳遞該請求,直到有一個對象處理它爲止。git
幾乎全部設計模式,在瞭解到它以前,筆者就已經在實戰中遇到過了,所以設計模式的確是從實踐中得出的真知。但另外一方面,若是沒有實戰的理解,單看設計模式是枯燥的,並且難以理解的,所以你們學習設計模式時,要結合實際問題思考。
若是看不懂上面的意圖介紹,沒有關係,設計模式須要在平常工做裏用起來,結合例子能夠加深你的理解,下面我準備了三個例子,讓你體會什麼場景下會用到這種設計模式。github
設想咱們要爲一個後端框架實現中間件(知道 Koa 的同窗能夠理解爲 Koa 的洋蔥模型),在代碼中能夠插入任意多箇中間件,每一箇中間件均可以對請求與響應進行處理。typescript
因爲每一箇中間件只響應本身感興趣的請求,所以只有運行時才知道這個中間件是否會處理請求,那麼中間件機制應該如何設計,才能保證其功能和靈活性呢?後端
若是一個大型系統中,任何一個模塊點擊都會彈出幫助文案,但並非每一個模塊都有幫助文案的,若是一個模塊沒有幫助文案,則顯示其父級的幫助文案,若是再沒有,就繼續冒泡到整個應用,展現應用級別的兜底幫助文案。這種系統應該如何設計?設計模式
其實 JS 事件冒泡機制就是個典型的職責鏈模式,由於任何 DOM 元素均可以監聽好比 onClick
,不只能夠本身響應事件,還可使用 event.stopPropagation()
阻止繼續冒泡。瀏覽器
JS 事件冒泡機制對前端來講太常見了,但咱們換個角度,站在點擊事件的角度理解,就能從新發現其設計的精妙之處:微信
點擊事件是疊加在每層 dom 上的,因爲 dom 對事件的處理和綁定是動態的,瀏覽器自己不知道哪些地方會處理點擊事件,但又要讓每層 dom 擁有對點擊事件的 「平等處理權」,因此就產生了冒泡機制,與事件阻止冒泡功能。框架
通用幫助文案和 JS 事件冒泡很相似,只是把點擊事件換成了彈出幫助文案罷了,其場景機理是同樣的。dom
說到這,咱們能夠再從新理解一下職責鏈模式的意圖:
意圖:使多個對象都有機會處理請求,從而避免請求的發送者和接收者之間的耦合關係。將這些對象連成一條鏈,並沿着這條鏈傳遞該請求,直到有一個對象處理它爲止。
請求指的是某個觸發機制產生的請求,是一個通用概念。「避免請求的發送者和接收者之間的耦合關係」,指的是若是咱們只有一個對象有處理請求的機會,那接收者就與發送者之間耦合了,其餘接收者必須經過這個接收者才能繼續處理,這種模式不夠靈活。
後半句描述的是如何設計,能夠實現這個靈活的模式,即將對象連成一條鏈,沿着鏈條傳遞該請求,直到有一個對象處理它爲止。還要理解到,任何一個對象都擁有阻斷請求繼續傳遞的能力。
在中間件機制的例子中,後端 Web 框架對 Http 請求的處理就是個運用職責鏈模式的典型案例,由於後端框架要處理的請求是平行關係,任何請求均可能要求被響應,但對請求的處理是經過插件機制拓展的,且對每一個請求的處理都是一個鏈條,存在處理、加工、再處理的邏輯關係。
Handler 就是對請求的處理,能夠看到這裏是一條環路,只要處理完以後就能夠交給下一個 Handler 進行處理,能夠在中途攔截後中斷,也能夠穿透整條鏈路。
ConcreteHandler
是具體 Handler 的實現,他們都須要繼承 Handler 以具有相同的 HandleRequest
方法,這樣每個處理中間件就都擁有了處理能力,使得這些對象連成的鏈條能夠對請求進行傳遞。
職責鏈實現方式很是多,好比 Koa 的洋蔥模型實現原理就值得再寫一篇文章,感興趣的同窗能夠閱讀 co 源碼。這裏僅介紹最簡單場景的實現方案。
職責鏈的簡單實現模式也分爲兩種,一種是每一個對象自己維護到下一個對象的引用,另外一種是由 Handler 維護後繼者。
下面例子使用 typescript 編寫。
`public class Handler {
private nextHandler: Handler
public handle() {
if(nextHandler) {
nextHandler.handle()
}
}
}
`
每一個 Handler 的默認行爲就是觸發下一個鏈條的 handle
,所以什麼都不作的話,這個鏈條是徹底打通的,所以咱們能夠在鏈條的任何一環進行處理。
處理的方式就是重寫 handle
函數,咱們在重寫時,能夠維持對 nextHandler.handle()
的調用,以使得鏈條繼續向後傳遞,也能夠不調用,從而終止鏈條向後傳遞。
職責鏈模式不保證每一箇中間件都有機會處理請求,由於中間件順序的問題,後面中間件可能被前面的中間件阻斷,所以當中間件之間存在不信任關係時,職責鏈模式並不能保證中間件調用的可靠性。
另外就是不要擴大設計模式的使用範圍,對一堆對象的連續調用就不必使用職責鏈模式,由於職責鏈適合處理對象數量不肯定、是否處理請求由每一個對象靈活決定的場景,而肯定了對象數量以及是否調用的場景,就不必使用職責鏈模式了。
職責鏈模式是插件機制經常使用的設計模式,在事件機制、請求處理中有普遍的應用。
職責鏈模式還能夠與組合模式組合使用,由於組合模式描述的是一種統一管理的樹形結構,每一個節點均可以把本身的父節點做爲後繼節點。實際上 dom 結構就是一種組合模式,事件冒泡就是在其基礎上拓展的職責鏈模式。
討論地址是: 精讀《設計模式 - Chain of Responsibility(職責鏈模式)》· Issue #292 · dt-fe/weekly
若是你想參與討論,請 點擊這裏,每週都有新的主題,週末或週一發佈。前端精讀 - 幫你篩選靠譜的內容。
關注 前端精讀微信公衆號
版權聲明:自由轉載-非商用-非衍生-保持署名( 創意共享 3.0 許可證)