設計原則是指導我們程式碼設計的一些經驗總結,也就是“心法”;物件導向就是我們的“武器”;設計模式就是“招式”。
以心法為基礎,以武器運用招式應對複雜的程式設計問題。
來吧,通過生活中一個小場景,一起系統學習這6大設計原則。
實習生表妹第一天去公司...
我:妹啊,第一天去公司感覺怎麼樣呢?
表妹:感覺同事們有些冷淡?
我:咋啦?
表妹:我在辦理入職的時候,和我對接的張同事突然有事走開了,我當時看另一位同事在聊微信,就麻煩他幫我辦理,但是他卻讓我等張同事回來。
我:原來是這樣子,首先,他不是你的直接對接人呀,其次,說不定他自己也有事情在處理呢。
這不很像我們軟體開發中的“迪米特法則”嘛?
每個模組只應該瞭解那些與它關係密切的模組的有限知識。或者說,每個模組只和自己的朋友“說話”,不和陌生人“說話”。也叫“最少知識原則”。
從上面的描述中,我們可以看出,迪米特法則包含前後兩個部分,如果我們把一個模組看作是一個人,那麼要實現“一個人應該對其他人有最少的瞭解”,應該做到這兩點:
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 }
你看,明星的直接朋友只有一個,也就是他的經紀人,無需瞭解粉絲和公司。這樣做有一個好處,就是能夠簡化物件與物件之間的通訊,進而減輕依賴,提供更高的靈活性,當然也可以提供一定的安全性。
總結
不該有直接依賴關係的類之間,不要有依賴;
有依賴關係的類之間,儘量只依賴必要的介面(也就是定義中的“有限知識”)。
好啦,不要為了應用設計原則而應用設計原則,我們在應用設計原則的時候,一定要具體問題具體分析。
參考
《大話設計模式》
《設計模式之禪》