最少知識原則

最少知識原則

最少知識原則(LKP)說的是一個軟件實體應當儘量少地與其餘實體發生相互做用。這
裏的軟件實體是一個廣義的概念,不只包括對象,還包括系統、類、模塊、函數、變量等。本
節咱們主要針對對象來講明這個原則,下面引用《面向對象設計原理與模式》一書中的例子來
解釋最少知識原則:
某軍隊中的將軍須要挖掘一些散兵坑。下面是完成任務的一種方式:將軍能夠通知
上校讓他叫來少校,而後讓少校找來上尉,並讓上尉通知一個軍士,最後軍士喚來一個
士兵,而後命令士兵挖掘一些散兵坑。
這種方式十分荒謬,不是嗎?不過,咱們仍是先來看一下這個過程的等價代碼:ajax

gerneral.getColonel( c ).getMajor( m ).getCaptain( c ) .getSergeant( s ).getPrivate( p ).digFoxhole();

讓代碼經過這麼長的消息鏈才能完成一個任務,這就像讓將軍經過那麼多繁瑣的步驟才能命
令別人挖掘散兵坑同樣荒謬!並且,這條鏈中任何一個對象的改動都會影響整條鏈的結果。
最有可能的是,將軍本身根本就不會考慮挖散兵坑這樣的細節信息。可是若是將軍真的考慮
了這個問題的話,他必定會通知某個軍官:「我不關心這個工做如何完成,可是你得命使人去挖
散兵坑。」設計模式

減小對象之間的聯繫

單一職責原則指導咱們把對象劃分紅較小的粒度,這能夠提升對象的可複用性。但愈來愈
多的對象之間可能會產生錯綜複雜的聯繫,若是修改了其中一個對象,極可能會影響到跟它相
互引用的其餘對象。對象和對象耦合在一塊兒,有可能會下降它們的可複用性。在程序中,對象
的「朋友」太多並非一件好事,「城門失火,殃及池魚」和「一人犯法,株連九族」的故事
時有發生。
最少知識原則要求咱們在設計程序時,應當儘可能減小對象之間的交互。若是兩個對象之間不
必彼此直接通訊,那麼這兩個對象就不要發生直接的相互聯繫。常見的作法是引入一個第三者對
象,來承擔這些對象之間的通訊做用。若是一些對象須要向另外一些對象發起請求,能夠經過第三
者對象來轉發這些請求。緩存

設計模式中的最少知識原則

最少知識原則在設計模式中體現得最多的地方是中介者模式和外觀模式,下面咱們分別進行
介紹。閉包

1. 中介者模式

在世界盃期間購買足球彩票,若是沒有博彩公司做爲中介,上千萬的人一塊兒計算賠率和輸贏
絕對是不可能的事情。博彩公司做爲中介,每一個人都只和博彩公司發生關聯,博彩公司會根據所
有人的投注狀況計算好賠率,彩民們贏了錢就從博彩公司拿,輸了錢就賠給博彩公司。
中介者模式很好地體現了最少知識原則。經過增長一箇中介者對象,讓全部的相關對象都通
過中介者對象來通訊,而不是互相引用。因此,當一個對象發生改變時,只須要通知中介者對象
便可。函數

2. 外觀模式

外觀模式,外觀模式在 JavaScript中的使用場景並很少。外觀模式主要是爲子系統中的一組接口提供一個一致的界面,外觀模式定義了一個高層接口,這個
接口使子系統更加容易使用.
外觀模式的做用是對客戶屏蔽一組子系統的複雜性。外觀模式對客戶提供一個簡單易用的高
層接口,高層接口會把客戶的請求轉發給子系統來完成具體的功能實現。大多數客戶均可以經過
請求外觀接口來達到訪問子系統的目的。但在一段使用了外觀模式的程序中,請求外觀並非強
制的。若是外觀不能知足客戶的個性化需求,那麼客戶也能夠選擇越過外觀來直接訪問子系統。
拿全自動洗衣機的一鍵洗衣按鈕舉例,這個一鍵洗衣按鈕就是一個外觀。若是是老式洗衣機,
客戶要手動選擇浸泡、洗衣、漂洗、脫水這 4個步驟。若是這種洗衣機被淘汰了,新式洗衣機的
漂洗方式發生了改變,那咱們還得學習新的漂洗方式。而全自動洗衣機的好處很明顯,無論洗衣
機內部如何進化,客戶要操做的,始終只是一個一鍵洗衣的按鈕。這個按鈕就是爲一組子系統所
建立的外觀。但若是一鍵洗衣程序設定的默認漂洗時間是 20 分鐘,而客戶但願這個漂洗時間是
30分鐘,那麼客戶天然能夠選擇越過一鍵洗衣程序,本身手動來控制這些「子系統」運轉。
外觀模式容易跟普通的封裝實現混淆。這二者都封裝了一些事物,但外觀模式的關鍵是定義
一個高層接口去封裝一組「子系統」。子系統在 C++或者 Java中指的是一組類的集合,這些類相
互協做能夠組成系統中一個相對獨立的部分。在 JavaScript中咱們一般不會過多地考慮「類」,如
果將外觀模式映射到 JavaScript中,這個子系統至少應該指的是一組函數的集合。
最簡單的外觀模式應該是相似下面的代碼:學習

var A = function(){
    a1();
    a2();
    }
    var B = function(){
    b1();
    b2();
    }
    var facade = function(){
    A();
    B();
    }
    facade();

許多 JavaScript設計模式的圖書或者文章喜歡把 jQuery的 $.ajax 函數看成外觀模式的實現,
這是不合適的。若是 $.ajax 函數屬於外觀模式,那幾乎全部的函數均可以被稱爲「外觀模式」。
問題是咱們根本沒有辦法越過 $.ajax 「外觀」去直接使用該函數中的某一段語句。
如今再來看看外觀模式和最少知識原則之間的關係。外觀模式的做用主要有兩點。
 爲一組子系統提供一個簡單便利的訪問入口。
 隔離客戶與複雜子系統之間的聯繫,客戶不用去了解子系統的細節。
從第二點來,外觀模式是符合最少知識原則的。好比全自動洗衣機的一鍵洗衣按鈕,隔開了
客戶和浸泡、洗衣、漂洗、脫水這些子系統的直接聯繫,客戶不用去了解這些子系統的具體實現。
假設咱們在編寫這個老式洗衣機的程序,客戶至少要和浸泡、洗衣、漂洗、脫水這 4個子系
統打交道。若是其中的一個子系統發生了改變,那麼客戶的調用代碼就得發生改變。而經過外觀
將客戶和這些子系統隔開以後,若是修改子系統內部,只要外觀不變,就不會影響客戶的調用。
一樣,對外觀的修改也不會影響到子系統,它們能夠分別變化而互不影響。es5

封裝在最少知識原則中的體現

封裝在很大程度上表達的是數據的隱藏。一個模塊或者對象能夠將內部的數據或者實現細
節隱藏起來,只暴露必要的接口 API 供外界訪問。對象之間不免產生聯繫,當一個對象必須引
用另一個對象的時候,咱們可讓對象只暴露必要的接口,讓對象之間的聯繫限制在最小的
範圍以內。
同時,封裝也用來限制變量的做用域。在 JavaScript中對變量做用域的規定是:
在es5以前,
1 變量在全局聲明,或者在代碼的任何位置隱式申明(不用 var ),則該變量在全局可見;
2 變量在函數內顯式申明(使用 var ),則在函數內可見。
把變量的可見性限制在一個儘量小的範圍內,這個變量對其餘不相關模塊的影響就越小,
變量被改寫和發生衝突的機會也越小。這也是廣義的最少知識原則的一種體現。
假設咱們要編寫一個具備緩存效果的計算乘積的函數 function mult (){} ,咱們須要一個對
象 var cache = {} 來保存已經計算過的結果。 cache 對象顯然只對 mult 有用,把 cache 對象放在
mult 造成的閉包中,顯然比把它放在全局做用域更加合適,代碼以下:prototype

var mult = (function(){
var cache = {};
return function(){
var args = Array.prototype.join.call( arguments, ',' );
if ( cache[ args ] ){
return cache[ args ];
}
var a = 1;
for ( var i = 0, l = arguments.length; i < l; i++ ){
a = a * arguments[i];
}
return cache[ args ] = a;
}
})();
mult( 3, 4, 5 ); // 輸出: 60

其實,最少知識原則也叫迪米特法則(Law of Demeter,LoD),「迪米特」這個名字源自 1987
年美國東北大學一個名爲「Demeter」的研究項目。
許多人更傾向於使用迪米特法則這個名字,也許是由於顯得更酷一點。但參考 Head First
Design Patterns的建議,稱之爲最少知識原則。一是由於這個名字更能體現其含義,另外一個緣由
是「法則」給人的感受是必須強制遵照,而原則只是一種指導,沒有哪條原則是在實際開發中必
須遵照的。好比,雖然遵照最小知識原則減小了對象之間的依賴,但也有可能增長一些龐大到難
以維護的第三者對象。跟單一職責原則同樣,在實際開發中,是否選擇讓代碼符合最少知識原則,
要根據具體的環境來定。設計

相關文章
相關標籤/搜索