一、介面隔離原則

使用多個介面,而不使用單一的介面,客戶端不應該依賴它不需要的介面。儘量的細化介面的職責,降低類的耦合度

我們先來看一個例子:

小明家附近新開了一家動物園,裡面有老虎、鳥兒、長頸鹿.....週末在逛動物園的時候,小明突發奇想,想用一種方式記錄一下這些動物的習性,於是他將老虎和鳥兒的習性結合了一下,寫了下面這段程式碼:

動物行為

// 動物行為
public interface Animal { // 吃
public void eat(); // 游泳
public void swim(); // 飛
public void fly();
}

老虎Tiger

// 老虎
public class Tiger implements Animal {
@Override
public void eat() {
System.out.println("老虎在吃雞肉.....");
} @Override
public void swim() {
System.out.println("老虎在游泳.....");
} @Override
public void fly() {
System.out.println("老虎不能飛.....");
}
}

小鳥Brid

// 小鳥
public class Brid implements Animal {
@Override
public void eat() {
System.out.println("小鳥在吃蟲子.....");
} @Override
public void swim() {
System.out.println("小鳥不會游泳.....");
} @Override
public void fly() {
System.out.println("小鳥正在飛.....");
}
}

寫完上面的三段程式碼後,小明發現了問題:在Animal介面的三個方法中,Tiger是不會飛的,所以fly()方法對於Tiger是沒有用的;Bird是不會游泳的,所以swim()方法對於Bird是沒有用的。這樣一來,Brid類和Tiger類都會空置一個方法,對於程式碼的結構設計來說不太合理。於是,他劃掉了上面的三段程式碼,仔細思索了一會兒,寫出了下面這幾段程式碼:

// 游泳
public interface ISwim {
public void swim();
} // 吃
public interface IEat {
public void eat();
} // 飛
public interface IFly {
public void fly();
}

小鳥Bird

// 小鳥
public class Brid implements IEat,IFly {
@Override
public void eat() {
System.out.println("小鳥在吃蟲子.....");
} @Override
public void fly() {
System.out.println("小鳥正在飛.....");
}
}

老虎Tiger

// 老虎
public class Tiger implements IEat,ISwim {
@Override
public void eat() {
System.out.println("老虎在吃雞肉.....");
} @Override
public void swim() {
System.out.println("老虎在游泳.....");
}
}

這樣來看,將eatswimfly三種方法拆分開來,分別放在三個不同的接口裡,這樣動物擁有哪幾種習性就實現哪幾個介面,不會再用空置的方法存在,這樣看起來也簡潔明瞭,來看看類圖:

二、迪米特法則

又被成為最少知道原則,指的是一個物件應該對其他物件保持最少的瞭解。一個實體類應當儘量少地和其他實體之間發生相互作用,使得系統模組相互獨立。形象來說就是:只和朋友交流,不和陌生人說話

迪米特法則認為,一個物件或方法,它只能夠呼叫以下物件:

  • 該物件本身
  • 作為引數傳進來的物件
  • 在方法內建立的物件

我們先來模擬一個超市購物的場景:顧客Customer到收銀臺結賬,收銀員PaperBoy負責收錢。

顧客的錢包Wallet

// 錢包
public class Wallet { // 錢包裡裝的錢
private Float value; // 構造器
public Wallet(Float value) {
this.value = value;
} // 獲得錢包裡的錢的金額
public Float getMoney(){
return this.value;
} // 付賬時 減錢
public void reduceMoney(Float money){
this.value -= money;
}
}

顧客Customer

// 顧客
public class Customer { private Wallet wallet = new Wallet(50f); public Wallet getWallet() {
return wallet;
}
}

收銀員PaperBoy

// 收銀員
public class PaperBoy { // 收銀員收錢
public void charge(Customer customer,Float money){
Wallet wallet = customer.getWallet();
if (wallet.getMoney() >= money){
System.out.println("顧客付賬:" + money +"元");
// 減去 應付的錢
wallet.reduceMoney(money);
System.out.println("錢包裡還剩:"+wallet.getMoney()+"元");
} else {
System.out.println("錢包裡的金額不夠......");
}
}
}

測試、執行

// 測試
public static void main(String[] args) {
PaperBoy paperBoy = new PaperBoy();
Customer customer = new Customer();
paperBoy.charge(customer,20f);
}



從測試程式碼和執行的結果來看,好像並沒有什麼問題。讓我們來看一下類圖:

從類圖中我們發現:PaperBoy類與Wallet類有著千絲萬縷的關係,顧客(Customer)的錢包(Wallet)好像並不是自己來控制的,而是由收銀員(PaperBoy)來決定的,就連錢包(Wallet)裡面的錢夠不夠也是由收銀員(PaperBoy)來判斷的;相當於顧客(Customer)將自己的錢包(Wallet)暴露給了收銀(PaperBoy),這樣來看,問題就很嚴重了,顧客(Customer)的隱私受到了侵犯,說大點就是民事糾紛,是可以上法庭的,可以通過法律追究責任的。所以我們思考良久,將上述程式碼改成下面這般:

錢包Wallet類不變顧客Customer去掉給出錢包的getWallet()方法,增加付錢的pay()方法

// 顧客
public class Customer { private Wallet wallet = new Wallet(50f); // 顧客自己付錢
public void pay(Float money){
if (wallet.getMoney() >= money){
System.out.println("顧客付賬:" + money +"元");
// 減去 應付的錢
wallet.reduceMoney(money);
System.out.println("錢包裡還剩:"+wallet.getMoney()+"元");
} else {
System.out.println("錢包裡的金額不夠......");
}
}
}

收銀員PaperBoy類中的charge()方法中的程式碼刪除原有的邏輯,改為呼叫顧客Customer類中的付錢pay()方法

// 收銀員
public class PaperBoy { // 收銀員收錢
public void charge(Customer customer,Float money){
customer.pay(money);
}
}

測試程式碼不變,我們再來看看類圖:

從類的結構圖來看:收銀員PaperBoy只和顧客Customer有聯絡,錢包Wallet只和顧客Customer有聯絡。再此情況下,如果把錢包Wallet也當作一個人來看的話,這個就是如下的關係:

  • 顧客Customer和錢包Wallet是朋友
  • 顧客Customer和收銀員PaperBoy是朋友
  • 錢包Wallet和收銀員PaperBoy是陌生人

這個就符合我們所說的迪米特法則中的核心:只和朋友交流,不和陌生人說話