設計原則之【迪米特法則】

Gopher大威發表於2022-03-01

設計原則是指導我們程式碼設計的一些經驗總結,也就是“心法”;物件導向就是我們的“武器”;設計模式就是“招式”。

以心法為基礎,以武器運用招式應對複雜的程式設計問題。

來吧,通過生活中一個小場景,一起系統學習這6大設計原則。

SOLID原則--SRP單一職責原則

SOLID原則--OCP開放封閉原則

SOLID法則--LSP裡式替換原則

SOLID原則--ISP介面隔離原則

SOLID原則--DIP依賴反轉原則

LOD迪米特法則

實習生表妹第一天去公司...

我:妹啊,第一天去公司感覺怎麼樣呢?

表妹:感覺同事們有些冷淡?

我:咋啦?

表妹:我在辦理入職的時候,和我對接的張同事突然有事走開了,我當時看另一位同事在聊微信,就麻煩他幫我辦理,但是他卻讓我等張同事回來。

我:原來是這樣子,首先,他不是你的直接對接人呀,其次,說不定他自己也有事情在處理呢。

這不很像我們軟體開發中的“迪米特法則”嘛?


每個模組只應該瞭解那些與它關係密切的模組的有限知識。或者說,每個模組只和自己的朋友“說話”,不和陌生人“說話”。也叫“最少知識原則”。

從上面的描述中,我們可以看出,迪米特法則包含前後兩個部分,如果我們把一個模組看作是一個人,那麼要實現“一個人應該對其他人有最少的瞭解”,應該做到這兩點:

1、只和直接的朋友交流;

2、減少對朋友的瞭解。

接下來就詳細說說如何做到這兩點。

首先,我們來看一下,什麼叫“朋友”?

軟體開發中的朋友:兩個物件之間的耦合關係稱之為“朋友”,通常有依賴、關聯、聚合和組合等。而直接朋友則通常表現為關聯、聚合和組合關係,即兩個物件之間聯絡更為緊密,通常以成員變數,方法的引數和返回值的形式出現。

減少對朋友的瞭解

一個類公開的public屬性或方法越多,修改時涉及的面也就越大,變更引起的風險擴散就越大。

就如同前面的場景,表妹只知道自己的直接對接人是負責給新員工辦理入職手續的,但是具體的操作,表妹是不知道的。

我們來看一下明星和粉絲互動的場景:

 1 // 粉絲類
 2 public class Fans {
 3  4     public void shakeHands(){
 5         System.out.println("與偶像握手");
 6     }
 7     public void sign(){
 8         System.out.println("偶像給我簽名");
 9     }
10     public void groupPhoto(){
11         System.out.println("與偶像合影");
12     }
13     
14     public void interaction(){
15         shakeHands();
16         sign();
17         groupPhoto();
18     }
19 }
20 21 // 偶像類
22 public class Star{
23     private Fans f;
24     
25     ...
26     
27     public void interactWithFans(){
28       // 現在偶像要和粉絲互動,正常來說,她只需要呼叫interaction()方法即可,
29       // 但是,她發現Fans所有的方法都是公開的,該如何互動呢?可能:
30         f.shakeHands();
31         f.sign();
32         f.groupPhoto();
33         
34         // 亦或是以下的操作 
35         f.sign();
36         f.groupPhoto();
37         
38         // 還可能是以下的操作
39         f.interaction();
40     }
41 }

你看,粉絲作為明星的朋友,公開了很多種互動方式,使得明星對粉絲的瞭解過多,這樣明星得花很大精力去考慮以哪種方式和粉絲互動。那麼,這裡的f物件應該暴露哪些方法呢?很顯然,對於明星Star來說,只需關注和粉絲的互動操作,而不關心具體是如何互動的,因此,只需要暴露interaction()方法。

那麼,上述的程式碼應該修改為:

 1 // 粉絲類
 2 public class Fans {
 3  4     private void shakeHands(){
 5         System.out.println("與偶像握手");
 6     }
 7     private void sign(){
 8         System.out.println("偶像給我簽名");
 9     }
10     private void groupPhoto(){
11         System.out.println("與偶像合影");
12     }
13     
14     public void interaction(){
15         shakeHands();
16         sign();
17         groupPhoto();
18     }
19 }
20 21 // 偶像類
22 public class Star{
23     private Fans f;
24     
25     ...
26     
27     public void interactWithFans(){
28         // 這時候,偶像她只管與粉絲互動就可以了,不管具體是握手、簽名還是合影。
29         f.interaction();
30     }
31 }

你看,這時明星和粉絲的互動就簡單多了。

通俗地講,一個類應該對自己需要耦合或呼叫的類知道得最少,我就知道你提供的這麼多public方法,我就呼叫這麼多,其他的我一概不關心。

其實,明星由於全身心投入藝術,所以許多日常事務由經濟人負責處理,如粉絲見面會,和媒體公司的業務洽談等。這裡的經紀人就是明星的直接朋友,粉絲和媒體公司是明星的間接朋友。

只和直接的朋友交流

現在,我們在剛才的場景中,加多一個經紀人類:

 1 // 粉絲類
 2 public class Fans {
 3  4     private void shakeHands(){
 5         System.out.println("與偶像握手");
 6     }
 7     private void sign(){
 8         System.out.println("偶像給我簽名");
 9     }
10     private void groupPhoto(){
11         System.out.println("與偶像合影");
12     }
13     
14     public void interaction(){
15         shakeHands();
16         sign();
17         groupPhoto();
18     }
19 }
20 21 // 經紀人類
22 public class Broker {
23     private Fans f;       // 負責粉絲見面會
24     private Company c;    // 負責商務洽談
25     ...
26     
27     // 開粉絲互動會
28     public void openInteraction() {
29         f.interaction();
30     }
31 }
32 33 // 偶像類
34 public class Star{
35     // 明星的經紀人
36     private Broker b;
37     
38     ...
39     
40     // 粉絲互動會,由經紀人打理
41     public void interactWithFans(){
42         b.openInteraction();
43     }
44 }

你看,明星的直接朋友只有一個,也就是他的經紀人,無需瞭解粉絲和公司。這樣做有一個好處,就是能夠簡化物件與物件之間的通訊,進而減輕依賴,提供更高的靈活性,當然也可以提供一定的安全性。

總結

不該有直接依賴關係的類之間,不要有依賴;

有依賴關係的類之間,儘量只依賴必要的介面(也就是定義中的“有限知識”)。

好啦,不要為了應用設計原則而應用設計原則,我們在應用設計原則的時候,一定要具體問題具體分析。

參考

《大話設計模式》

《設計模式之禪》

https://www.jianshu.com/p/14589fb6978e

https://www.itheima.com/news/20210819/173818.html

相關文章