依賴倒置原則(Dependence Inversion Priiciple,DIP) 介紹 High level modules should not depend upon low level modules. Both should depend upon abstractions. Abstr ...
依賴倒置原則(Dependence Inversion Priiciple,DIP)
介紹
High level modules should not depend upon low level modules. Both should depend upon abstractions. Abstractions should not depend upon details. Detatils should depend upon abstractions.
翻譯過來有是三個意思:
1.高層模塊不應該依賴底層模塊,兩者都應該依賴其抽象。
2.抽象不應該依賴細節。
3.細節應該依賴抽象。
在Java中,表現就是:
1.模塊間的依賴通過抽象發生,實現類之間不應該發生直接的依賴關機,其依賴關係應該是用過介面或者抽象類產生的;
2.介面或者抽象類不應該依賴實現類;
3.實現類應該依賴介面或者抽象類。
依賴倒置原則的設計理念是:相較於實習類具有多變性,抽象要穩定的多。框架的設計應該基於抽象,這樣子,能提高項目的穩定性。
在框架中,抽象的作用是用來制定規範,具體的細節應該交給實現類。
應用實例
有一個司機類對象張三(zs),具有drive方法來駕駛汽車。
public class Dependence1 {
public static void main(String[] args) {
Driver zs = new Driver();
Benz benz = new Benz();
zs.drive(benz);
}
}
class Driver {
public void drive(Benz benz) {
benz.run();
}
}
class Benz {
public void run() {
System.out.println("賓士汽車發動...");
}
}
//經過艱苦奮鬥,張三同志買了一輛寶馬汽車
class BMW {
public void run() {
System.out.println("寶馬汽車發動...");
}
}
目前為止,看上去很美好,正常的功能也實現了;但是,因為這個功能是基於具體的實現類Benz實現的,這就為後來的擴展帶來了麻煩:比如張三同志艱苦奮鬥,又買了一輛寶馬(BMW),但是根據Driver類的drive方法,張三同志不能駕駛新買的寶馬汽車。這就是很嚴重的邏輯了:只要是有了駕照,賓士和寶馬應該都能駕駛。
改進措施:
很明顯,司機類中的drive方法不應該依賴於一種具體品牌的汽車,而因該是汽車的泛指。所以,新建兩個介面:
IDriver和ICar,分別定義了司機和汽車的職能,汽車就是駕駛汽車。具體的代碼如下:
public class Dependence2 {
public static void main(String[] args) {
IDriver zs = new Driver();
ICar benz = new Benz();
zs.drive(benz);
ICar bmw = new BMW();
zs.drive(bmw);
}
}
interface ICar {
//是汽車都應該具備的功能
public void run();
}
class Benz implements ICar {
@Override
public void run() {
System.out.println("賓士汽車發動...");
}
}
class BMW implements ICar {
@Override
public void run() {
System.out.println("寶馬汽車發動...");
}
}
interface IDriver {
//是司機就應該會開車,不管是什麼車
public void drive(ICar iCar);
}
class Driver implements IDriver {
@Override
public void drive(ICar iCar) {
iCar.run();
}
}
在demo中,類Dependence2 作為高層模塊,它對底層模塊的依賴建立在抽象上;司機張三的錶面類型時IDriver,Benz和BMW的錶面類型是ICar,這樣做,在擴展業務邏輯(比如新增一輛汽車Mini)時,只需修改業務場景類(高層模塊),對底層模塊如Driver和Benz等沒有影響。
依賴的三種形式
依賴的形式有三種:介面依賴、setter方法依賴和構造器依賴。具體介紹如下:
1.介面依賴
顧名思義,就是通過實現介面的方式註入依賴,代碼詳見上面的改進措施。
2.setter方法依賴
在抽象中定義setter方法,就是所謂的setter方法依賴。
demo如下:
interface IDriver {
//setter方式註入
public void setICar(ICar iCar);
}
class Driver implements IDriver {
private ICar iCar;
@Override
public void setICar(ICar iCar) {
this.iCar = iCar;
}
}
3.構造器依賴
這個也比較好理解,就是將ICar的具體類型,通過構造器傳給Driver:
class Driver implements IDriver {
private ICar iCar;
public Driver(ICar iCar) {
this.iCar =iCar;
}
}
註意事項和細節
在項目中,底層模塊的類都應該有抽象類或者介面,或者兩者都有;
變數的聲明應該是抽象類型,有利於提高項目的穩定性;
任何類都不應該從具體類派生;
儘量不要重寫積累的方法,要結合“里氏替換原則”使用。