1、疑惑
在我們剛開始學習程式設計的時候,通常會將所有的方法都宣告為public,例如:
package com.fanqiekt.principle.lod;
/**
* 廚師
*
* @author 番茄課堂-懶人
*/
public class Chef{
public String flavour = "祕製調料XXX";
/**
* 做飯
* @param dishName 下單的菜名
*/
public void cooking(String dishName) {
System.out.println("開始烹飪:"+dishName);
switch (dishName){
case "蕃茄炒雞蛋":
cookingTomato();
break;
case "酸辣土豆絲":
cookingPotato();
break;
}
System.out.println(dishName + "出鍋");
}
/**
* 炒蕃茄雞蛋
*/
public void cookingTomato() {
System.out.println("放入調料:" + flavour);
System.out.println("先炒雞蛋");
System.out.println("再炒蕃茄");
System.out.println("...");
}
/**
* 炒酸辣土豆絲
*/
public void cookingPotato() {
System.out.println("放入調料:" + flavour);
System.out.println("先放蔥薑蒜");
System.out.println("再放土豆絲");
System.out.println("...");
}
}
複製程式碼
廚師類。
package com.fanqiekt.principle.lod;
/**
* 客人
* @Author: 番茄課堂-懶人
*/
public class Client {
public static void main(String[] args){
Chef chef = new Chef();
chef.cooking("蕃茄炒雞蛋");
System.out.println("-------");
chef.cooking("酸辣土豆絲");
}
}
複製程式碼
客人類。
這樣做好不好?
大家可以先思考下。
2、定義
我們先來看一下迪米特法則的定義。
又稱為最少知識原則。
一個軟體實體應當儘可能少地與其他實體發生相互作用。
這個比較好理解,一個類儘可能少的與其他的類產生關聯,低耦合,高內聚嘛。
迪米特法則包含兩種角色:依賴者與被依賴者。
3、含義
我們回到疑惑中的問題,Chef類好不好?
首先,Chef類的角色是被依賴者。
它暴露了flavour屬性,這是存在問題的,有哪個廚師願意把自己的獨家配方公開出去啊。
而且它還暴露了依賴者並不關心cookingTomato、cookingPotato兩個方法。
對於依賴者來說,我只需要呼叫cooking方法就可以了,至於菜具體怎麼做,就與我無關了。
並且暴露的話,程式設計師也容易懵逼,這兩個方法是幹嘛的?我要不要研究下?
所以,
從被依賴者的角度來說:只暴露應該暴露的方法或者屬性。
有個簡單的套路:
可以用private就絕不用protected,可以用protected就絕不用public。
那Client類總沒什麼問題了吧。
確實,乍一看感覺沒有任何問題的,再乍乍一看還是感覺沒有問題。。。
它的不合適不是從語法呼叫方面看的,而是從依賴關係。
客人是不可以直接依賴廚師的,而應該依賴服務員。
在實際專案中,很可能會存在客人類依賴了廚師類、服務員類,而服務員類又依賴了廚師類。
這會讓程式碼非常混亂,也違背了迪米特法則。
所以,
從依賴者的角度來說:只依賴應該依賴的物件。
4、程式碼
我們按照迪米特法則優化下程式碼。
package com.fanqiekt.principle.lod;
/**
* 廚師
*
* @author 番茄課堂-懶人
*/
public class Chef{
private String flavour = "祕製調料XXX";
/**
* 做飯
* @param dishName 下單的菜名
*/
public void cooking(String dishName) {
System.out.println("開始烹飪:"+dishName);
switch (dishName){
case "蕃茄炒雞蛋":
cookingTomato();
break;
case "酸辣土豆絲":
cookingPotato();
break;
}
System.out.println(dishName + "出鍋");
}
/**
* 炒蕃茄雞蛋
*/
private void cookingTomato() {
System.out.println("放入調料:" + flavour);
System.out.println("先炒雞蛋");
System.out.println("再炒蕃茄");
System.out.println("...");
}
/**
* 炒酸辣土豆絲
*/
private void cookingPotato() {
System.out.println("放入調料:" + flavour);
System.out.println("先放蔥薑蒜");
System.out.println("再放土豆絲");
System.out.println("...");
}
}
複製程式碼
flavour宣告為private,其他類就不可訪問了,避免洩漏祕製調料。
cookingTomato、cookingPotato宣告為private
cooking需要依賴者呼叫,所以依舊為public。
package com.fanqiekt.principle.lod;
/**
* 服務員
*
* @author 番茄課堂-懶人
*/
public class Waiter {
private Chef chef = new Chef();
/**
* 點餐
* @param dishName 餐名
*/
public void order(String dishName) {
System.out.println("客人點餐:"+dishName);
chef.cooking(dishName);
System.out.println(dishName+"上桌啦,請您品嚐!");
}
}
複製程式碼
服務員類,依賴了Chef物件,並宣告為private。
package com.fanqiekt.principle.lod;
/**
* 客人
* @Author: 番茄課堂-懶人
*/
public class Client {
public static void main(String[] args){
Waiter waiter = new Waiter();
waiter.order("蕃茄炒雞蛋");
System.out.println("-------");
waiter.order("酸辣土豆絲");
}
}
複製程式碼
客人類,依賴了Waiter類。。
客人點餐:蕃茄炒雞蛋
開始烹飪:蕃茄炒雞蛋
放入調料:祕製調料XXX
先炒雞蛋
再炒蕃茄
...
蕃茄炒雞蛋出鍋
蕃茄炒雞蛋上桌啦,請您品嚐!
-------
客人點餐:酸辣土豆絲
開始烹飪:酸辣土豆絲
放入調料:祕製調料XXX
先放蔥薑蒜
再放土豆絲
...
酸辣土豆絲出鍋
酸辣土豆絲上桌啦,請您品嚐!
複製程式碼
執行結果。
5、優點
降低風險
避免不該暴露的方法或者屬性暴露,從而規避風險。
避免依賴關係過於混亂。
6、嘻哈說
接下來,請您欣賞迪米特法則的原創歌曲。
嘻哈說:迪米特法則
作曲:懶人
作詞:懶人
Rapper:懶人
哥們是個大廚
身材有些發福
您可以讓我做飯甚至是打滷
但您無權知曉我具體是油煎炸煮
這是我的祕密才能把客人抓住
這就是最小知識原則的迪米特法則
一個實體盡少與其他產生瓜葛
依賴者只依賴應該依賴的物件絕對可以減少bug
被依賴者只暴露該暴露的屬性還有方法呢
把風險被降低絕對不可能是假的
複製程式碼
閒來無事聽聽曲,知識已填腦中去;
學習複習新方式,頭戴耳機不小覷。
番茄課堂,學習也要酷。