菜雞與物件導向 (15): 最少知識原則
在上一篇我們紀錄了依賴反轉原則,到此五大原則介紹完畢…是這樣嗎?太天真了!就像四天王總是五個人一樣,五大原則當然也有第六個!
今天的主角就是五大原則中L位的第一候補:最少知識原則,也被稱作迪米特法則。
最少知識原則 (Least Knowledge Principle)
只和直接的朋友溝通,不和陌生人說話
那麼所謂的朋友是什麼呢?就是指這個物件或方法有直接相關的物件啦。例如當我們使用一個方法時,這個方法應該只認識:
- 該方法所屬的類別
- 該方法所接收的參數
- 該方法中建立的類別
- 該方法所屬的類別所依賴的對象
除此之外對這個方法而言都是陌生人。什麼情況會遇到陌生人呢?有一個蠻常遇到的狀況就符合定義:當我們使用依賴對象的方法,該方法給了我們另一個類別時,我們就正在接觸毫無關係的陌生人。
這個原則的要求就是:不要跟陌生人說話,就算是朋友介紹了他的朋友給你也一樣,不認識就是不認識,更不能拿陌生人的東西。換個方式就是說:不應該使用其他類別的方法所回傳的類別的方法。
用文字的可能會有點繞口令,簡單來說就是像 Foo.GetBoo().BooDoSomeThing()
這種情況,我們不該去跟 Foo
要 Boo
回來然後使用 Boo
的方法,因為我們只認識 Foo
,而不認識 Boo
。
畢竟,很多時候我們不該直接插手控制:
- 主人可以叫狗坐下,但主人不應該直接控制狗的腿坐下
- 當我們按下牆壁的開關時,是希望燈直接打開。而不是彈出兩條電線讓你自己接起來
- 當我們去餐廳時,會讓服務生替你把要求的餐點交給廚師烹調,而不是我們直接殺進去廚房對著廚師吼「你給我煮啊!」
這種直接叫廚師煮給你看、甚至自己搶過來煮的做法,就是平常直接伸手進去其他模組的控制狂、完全和 封裝 的概念背道而馳。
腿的動作就應該讓狗去自己控制,讓燈泡亮就應該隱藏在開關之後。物件就該只和直接的朋友溝通。
除了只和直接的朋友溝通,也就是只和直接依賴的類別互動,這個互動也是要講究一點的。畢竟朋友之間也還是會有共通的默契和距離,類別之間的互動也應該只做必要的溝通。
這就是我們在封裝提過的「給程式碼隱私的空間」:為了避免物件之間的互動情況過於複雜,我們應該加以控制,把各自的工作封裝在各自的物件內部,使其只有必要的往來。
因此最少知識原則就要求了:一個物件應該對其他物件應該只有最少的了解。
到這邊讓我們稍微整理一下:
- 只和直接的朋友溝通,不和陌生人說話:物件或方法應該只和自己及直接接觸的對象互動
- 不應該使用其他類別的方法回傳的類別的方法:不該破壞封裝並造成額外且違反邏輯的互動
- 一個物件對其他物件應該只有最少的了解:類別只開放 (Public) 必要的功能,並且類別之間應該只有必要的互動
也就是說:只依賴應該依賴的對象,只開放應該開放的方法。
聰明的朋友應該能從這邊看出最少知識原則的核心理念了,就是解除耦合。
我們在 耦合篇 提過,物件彼此有關聯就會產生耦合,而不好的耦合就會散發出臭味。為了方便管理和降低複雜性,減少臭味出現的機率,我們的目標就是追求耦合。
相對於 依賴反轉原則 利用 抽象和介面 的方式在模組之間做出隔離和控制的作法。最少知識原則則是利用 封裝 的概念來解除耦合,畢竟,關聯越少耦合也越少嘛。
所以我們可以說:良好的封裝就是符合最少知識原則的封裝。複雜性隱藏到自己內部,對外只開放必要的功能,並且只使用到直接關聯的對象,確保不會造成意外的耦合,且讓關聯的模組之間更加靠攏。如此一來,就能夠更加提高內聚、降低耦合了。
然而,為了好好地切分朋友和陌生人,也可能會變成需要建立更多的中間類別,或是更多的依賴關係。
例如人原本可以直接把電線接起來讓燈泡亮起來,但為了把電線使燈泡變亮這件事的複雜度封裝起來,我們就必須要有一個開關,再把電線放到開關後面去,變成了人按下開關,開關藉由電線點亮燈炮等等,整體來說會使系統內的類別變多。
因此,在設計的時候也必須要考量到整個方法串的深度,可以用 單一職責 的角度下去衡量。請不要越封裝越細,類別越做越多,反而變成過度設計了。
那麼,今天就記錄到這裡。由於最少知識原則的概念,大多在封裝篇和耦合篇的時候就已經偷渡完了,所以這邊就針對觀念簡單介紹,實務上處理類別間的耦合時,就可以稍微從最少知識原則的角度想一想,一定會有幫助的。那麼,我們下次見~
本系列下一篇:菜雞與物件導向 (Ex1): 小結
參考資料
- [ASP.NET]91之ASP.NET由淺入深 不負責講座 Day19 - LoD/LKP 最少知識原則 - In 91
- [CK Patt 設計模式#11] 迪米特法則(Demeter Law)
- 最小知識原則 - Yuchi 的學習筆記
- Object Oriented物件導向設計原則SOLID-3:Law of Demeter(LoD) 狄米特法則 - Sian
- 迪米特法則——面向對象設計原則
- 最少知识原则(Least Knowledge Principle) - 熵碼匠藝
- 封裝與迪米特法則 - 林信良
同系列文章
- 菜雞與物件導向 (0): 前言
- 菜雞與物件導向 (1): 類別、物件
- 菜雞與物件導向 (2): 建構式、多載
- 菜雞與物件導向 (3): 封裝
- 菜雞與物件導向 (4): 繼承
- 菜雞與物件導向 (5): 多型
- 菜雞與物件導向 (6): 抽象、覆寫
- 菜雞與物件導向 (7): 介面
- 菜雞與物件導向 (8): 內聚、耦合
- 菜雞與物件導向 (9): SOLID
- 菜雞與物件導向 (10): 單一職責原則
- 菜雞與物件導向 (11): 開放封閉原則
- 菜雞與物件導向 (12): 里氏替換原則
- 菜雞與物件導向 (13): 介面隔離原則
- 菜雞與物件導向 (14): 依賴反轉原則
- 菜雞與物件導向 (15): 最少知識原則
- 菜雞與物件導向 (Ex1): 小結
其他文章
哈囉,如果你也有 LikeCoin,也覺得我的文章有幫上忙的話,還請不吝給我拍拍手呦,謝謝~ ;)