依賴反轉原則(DIP)的定義有兩點:
1. High-level modules should not depend on low-level modules. Both should depend on abstractions.
翻譯年糕:高層模組不應該依賴低層模組,兩者皆應依賴於抽象。
2. Abstractions should not depend on details. Details should depend on abstractions.
翻譯年糕:抽象不應該依賴細節,細節應該依賴於抽象。
高層低層是相對關係,其實也就是呼叫者與被呼叫者。而細節指的是具體的實作,相較於抽象的穩定,細節的變化較多。
比如說,到賣場消費要付款時,我使用信用卡付款:
class Payment{
public void pay(CreditCard creditCard){
creditCard.pay();
}
}
class CreditCard{
public void pay(){
System.out.println("信用卡付款");
}
}
public class Bank {
public static void main(String args[]) {
Payment p = new Payment();
p.pay(new CreditCard());
}
}
output
信用卡付款
依照上面的程式碼,就順利的使用信用卡完成了付款了!信用卡即是低層次模組,而付款這個行為就是高層次模組。可以發現付款這個行為跟信用卡有直接的關係。想想我們從以前用現金、金融卡、信用卡到現在電子支付甚至虛擬貨幣...等等。隨著時代的進步,會有更多的付款方式出現,但如果照著上面的方式去撰寫系統的話,每當出現一個新的付款方式,就要去更動一次程式,這不是個理想的狀態。
上述提到,付款依附著信用卡,並不是我們想看到的。於是我們可以將付款行為抽出:
interface IPayment{
public void pay();
}
class CreditCard implements IPayment{
public void pay(){
System.out.println("信用卡付款");
}
}
class QRCode implements IPayment{
public void pay(){
System.out.println("QRCode付款");
}
}
class Payment{
public void pay(IPayment iPayment){
iPayment.pay();
}
}
public class Bank {
public static void main(String args[]) {
Payment p = new Payment();
p.pay(new CreditCard());
p.pay(new QRCode());
}
}
output
信用卡付款
QRCode付款
經過以上的修改,抽出了一個IPaymeny作為interface,付款方式CreditCard和QRCode去實作IPayment,而Payment只要將只要將IPayment引入即可。在實作前他不需要知道付款方式是什麼,在實作時把對應的方式放入即可。如此一來,假設未來要增加虛擬貨幣的付款,只需要新增一個blockchain的class即可,不需要再動到Payment。
剛剛我們一直在解釋定義的第一點,而第二點抽象不應該依賴細節,細節應該依賴於抽象
又是什麼意思呢?我們可以把信用卡以及QRCode看成付款的細節(變化度高),而這兩個付款方式應該依照著抽象類別(穩定度高)IPayment去實作,而不是IPayment去照著信用卡或是QRCode的方向走。
1. 减少class間的耦合性,提高系统的穩定性
2. 降低開發時的風險
3. 提高系統可讀及維護性
高層模組(Payment)不應該依賴低層模組(CreditCard),兩者皆應依賴於抽象(IPayment)
抽象(IPayment)不應該依賴細節(CreditCard),細節(CreditCard)應該依賴於抽象(IPayment)
依賴倒置原則 (Dependency-Inversion Principle, DIP)
依賴反轉原則
依賴反轉原則 Dependency Inversion Principle (DIP)
SOLID 原則 - Dependency Inversion Principle(依賴反轉原則)
依赖倒置原则DIP