1. 程式人生 > >設計模式之職責鏈模式

設計模式之職責鏈模式

如何 設計模式 bili script 處理 dom 查找 dialog 關系

設計模式之職責鏈模式

May 16, 2015

職責鏈模式(Chain of responsibility)是使多個對象都有機會處理請求,從而避免請求的發送者和接受者之間的耦合關系。將這個對象連成一條鏈,並沿著這條鏈傳遞該請求,直到有一個對象處理他為止。

也就是說,請求以後,從第一個對象開始,鏈中收到請求的對象要麽親自處理它,要麽轉發給鏈中的下一個候選者。提交請求的對象並不明確知道哪一個對象將會處理它——也就是該請求有一個隱式的接受者(implicit receiver)。根據運行時刻,任一候選者都可以響應相應的請求,候選者的數目是任意的,你可以在運行時刻決定哪些候選者參與到鏈中。

正文

對於 JavaScript 實現,我們可以利用其原型特性來實現職責鏈模式。

var NO_TOPIC = -1; var Topic; function Handler(s, t) { this.successor = s || null; this.topic = t || 0; } Handler.prototype = { handle: function () { if (this.successor) { this.successor.handle() } }, has: function () { return this.topic != NO_TOPIC; } };

Handler 只是接受 2 個參數,第一個是繼任者(用於將處理請求傳下去),第二個是傳遞層級(可以用於控制在某個層級下是否執行某個操作,也可以不用),Handler 原型暴露了一個 handle 方法,這是實現該模式的重點,先來看看如何使用上述代碼。

var app = new Handler({ handle: function () { console.log(‘app handle‘); } }, 3); var dialog = new Handler(app, 1); var button = new Handler(dialog, 2); button.handle();

改代碼通過原型特性,調用代碼從 button.handle()->dialog.handle()->app.handle()->參數裏的 handle(),前三個都是調用原型的 handle,最後才查找到傳入的參數裏的 handle,然後輸出結果,也就是說其實只有最後一層才處理。

那如何做到調用的時候,只讓 dialog 的這個對象進行處理呢?其實可以定義 dialog 實例對象的 handle 方法就可以了,但需要在 new button 的之前來做,代碼如下:

var app = new Handler({ handle: function () { console.log(‘app handle‘); } }, 3); var dialog = new Handler(app, 1); dialog.handle = function () { console.log(‘dialog before ...‘) // 這裏做具體的處理操作 console.log(‘dialog after ...‘) }; var button = new Handler(dialog, 2); button.handle();

該代碼的執行結果即時 dialog.handle 裏的處理結果,而不再是給 app 傳入的參數裏定義的 handle 的執行操作。

那能不能做到自身處理完以後,然後在讓繼任者繼續處理呢?答案是肯定的,但是在調用的 handle 以後,需要利用原型的特性調用如下代碼:

Handler.prototype.handle.call(this);

該句話的意思說,調用原型的 handle 方法,來繼續調用其繼任者(也就是 successor )的 handle 方法,以下代碼表現為:button/dialog/app 三個對象定義的 handle 都會執行。

var app = new Handler({ handle: function () { console.log(‘app handle‘); } }, 3); var dialog = new Handler(app, 1); dialog.handle = function () { console.log(‘dialog before ...‘) // 這裏做具體的處理操作 Handler.prototype.handle.call(this); //繼續往上走 console.log(‘dialog after ...‘) }; var button = new Handler(dialog, 2); button.handle = function () { console.log(‘button before ...‘) // 這裏做具體的處理操作 Handler.prototype.handle.call(this); console.log(‘button after ...‘) }; button.handle();

通過代碼的運行結果我們可以看出,如果想先自身處理,然後再調用繼任者處理的話,就在末尾執行 Handler.prototype.handle.call(this); 代碼,如果想先處理繼任者的代碼,就在開頭執行 Handler.prototype.handle.call(this); 代碼。

總結

職責鏈模式經常和組合模式一起使用,這樣一個構件的父構件可以作為其繼任者。

同時,DOM 裏的事件冒泡機制也和此好像有點類似,比如點擊一個按鈕以後,如果不阻止冒泡,其 click 事件將一直向父元素冒泡,利用這個機制也可以處理很多相關的問題,比如本系列設計模式享元模式裏的《例1:事件集中管理》的示例代碼。

設計模式之職責鏈模式