依賴倒置原則(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.
翻譯過來有是三個(gè)意思:
1.高層模塊不應(yīng)該依賴底層模塊柴我,兩者都應(yīng)該依賴其抽象骨坑。
2.抽象不應(yīng)該依賴細(xì)節(jié)羞海。
3.細(xì)節(jié)應(yīng)該依賴抽象厘灼。
在Java中够坐,表現(xiàn)就是:
1.模塊間的依賴通過抽象發(fā)生摇邦,實(shí)現(xiàn)類之間不應(yīng)該發(fā)生直接的依賴關(guān)機(jī)汞窗,其依賴關(guān)系應(yīng)該是用過接口或者抽象類產(chǎn)生的;
2.接口或者抽象類不應(yīng)該依賴實(shí)現(xiàn)類刊苍;
3.實(shí)現(xiàn)類應(yīng)該依賴接口或者抽象類靖苇。
依賴倒置原則的設(shè)計(jì)理念是:相較于實(shí)習(xí)類具有多變性,抽象要穩(wěn)定的多班缰。框架的設(shè)計(jì)應(yīng)該基于抽象悼枢,這樣子埠忘,能提高項(xiàng)目的穩(wěn)定性。
在框架中馒索,抽象的作用是用來制定規(guī)范莹妒,具體的細(xì)節(jié)應(yīng)該交給實(shí)現(xiàn)類。
應(yīng)用實(shí)例
有一個(gè)司機(jī)類對(duì)象張三(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("奔馳汽車發(fā)動(dòng)...");
}
}
//經(jīng)過艱苦奮斗,張三同志買了一輛寶馬汽車
class BMW {
public void run() {
System.out.println("寶馬汽車發(fā)動(dòng)...");
}
}
目前為止蜈块,看上去很美好鉴腻,正常的功能也實(shí)現(xiàn)了迷扇;但是,因?yàn)檫@個(gè)功能是基于具體的實(shí)現(xiàn)類Benz實(shí)現(xiàn)的爽哎,這就為后來的擴(kuò)展帶來了麻煩:比如張三同志艱苦奮斗蜓席,又買了一輛寶馬(BMW),但是根據(jù)Driver類的drive方法课锌,張三同志不能駕駛新買的寶馬汽車厨内。這就是很嚴(yán)重的邏輯了:只要是有了駕照,奔馳和寶馬應(yīng)該都能駕駛渺贤。
改進(jìn)措施:
很明顯雏胃,司機(jī)類中的drive方法不應(yīng)該依賴于一種具體品牌的汽車,而因該是汽車的泛指志鞍。所以瞭亮,新建兩個(gè)接口:
IDriver和ICar,分別定義了司機(jī)和汽車的職能述雾,汽車就是駕駛汽車街州。具體的代碼如下:
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 {
//是汽車都應(yīng)該具備的功能
public void run();
}
class Benz implements ICar {
@Override
public void run() {
System.out.println("奔馳汽車發(fā)動(dòng)...");
}
}
class BMW implements ICar {
@Override
public void run() {
System.out.println("寶馬汽車發(fā)動(dòng)...");
}
}
interface IDriver {
//是司機(jī)就應(yīng)該會(huì)開車,不管是什么車
public void drive(ICar iCar);
}
class Driver implements IDriver {
@Override
public void drive(ICar iCar) {
iCar.run();
}
}
在demo中玻孟,類Dependence2 作為高層模塊唆缴,它對(duì)底層模塊的依賴建立在抽象上;司機(jī)張三的表面類型時(shí)IDriver黍翎,Benz和BMW的表面類型是ICar面徽,這樣做,在擴(kuò)展業(yè)務(wù)邏輯(比如新增一輛汽車Mini)時(shí)匣掸,只需修改業(yè)務(wù)場景類(高層模塊)趟紊,對(duì)底層模塊如Driver和Benz等沒有影響。
依賴的三種形式
依賴的形式有三種:接口依賴碰酝、setter方法依賴和構(gòu)造器依賴霎匈。具體介紹如下:
1.接口依賴
顧名思義,就是通過實(shí)現(xiàn)接口的方式注入依賴送爸,代碼詳見上面的改進(jìn)措施铛嘱。
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.構(gòu)造器依賴
這個(gè)也比較好理解墨吓,就是將ICar的具體類型,通過構(gòu)造器傳給Driver:
class Driver implements IDriver {
private ICar iCar;
public Driver(ICar iCar) {
this.iCar =iCar;
}
}
注意事項(xiàng)和細(xì)節(jié)
在項(xiàng)目中纹磺,底層模塊的類都應(yīng)該有抽象類或者接口帖烘,或者兩者都有;
變量的聲明應(yīng)該是抽象類型橄杨,有利于提高項(xiàng)目的穩(wěn)定性秘症;
任何類都不應(yīng)該從具體類派生照卦;
盡量不要重寫積累的方法,要結(jié)合“里氏替換原則”使用历极。