依賴倒置(Dependence Inversion Principle,DIP)
High level modules should not deppend oupon low level modules.Both should depend upon abstractions.Abstractions should not depend upon details.Details should depend upon abstractions.
定義中有三層含義:
- 高層模塊不應(yīng)該依于低層模塊蛋哭,兩者都應(yīng)該依賴于其抽象鞠苟。
- 抽象不應(yīng)該依賴細(xì)節(jié)沧竟。
-
細(xì)節(jié)應(yīng)該依賴抽象哥童。
理解: 高層模塊相對低層模塊而言抹镊。低層模塊是不可細(xì)分的原子邏輯模塊任斋。其組裝即是高層模塊。
面向?qū)ο蟮恼Z言中露筒,抽象就是接口或者抽象類呐伞,不能被實(shí)例化。細(xì)節(jié)就是繼承抽象類或?qū)崿F(xiàn)接口而產(chǎn)生的類慎式,可以被實(shí)例化伶氢。
java中依賴倒置原則的體現(xiàn):
1. 模塊之間的依賴通過抽象發(fā)生,實(shí)現(xiàn)類直接不直接發(fā)生依賴關(guān)系瞬捕,依賴是通過接口和抽象類產(chǎn)生的鞍历。
2. 接口和抽象類不依賴于實(shí)現(xiàn)類
3. 實(shí)現(xiàn)類依賴于借口或者抽象類
即--面向接口編程 。
案例分析:程序員一般都是多技能型的肪虎,在工作時(shí)會(huì)使用多種編程語言,不同語言的代碼會(huì)以不同的語法運(yùn)行惧蛹。因此有這么一個(gè)業(yè)務(wù)場景扇救,程序員使用不同的語言進(jìn)行編程,代碼以不同的語法運(yùn)行香嗓。
這里有三類對象迅腔,編程語言-程序員-業(yè)務(wù)場景
image.png
代碼:
Coder.java
public class Coder {
public void code(Java java){
java.run();
}
}
Java.java
public class Java {
public void run(){
System.out.println("代碼以Java的語法運(yùn)行~");
}
}
Client.java
public class Client {
public static void main(String[] args) {
Coder coderA = new Coder();
Java java = new Java();
coderA.code(java);
}
}
這里存在一個(gè)問題,如果我們的系統(tǒng)擴(kuò)展的比較大:存在多種程序員靠娱,如后端工程師沧烈,前端工程師,每種程序員的技術(shù)棧不一樣像云,每種語言的語法也都不一樣锌雀,那我們的程序員Coder類的code方法需要根據(jù)語言的不同重載很多個(gè)版本才能滿足程序員使用多種語言進(jìn)行編程的需求。這樣一來迅诬,每次增加一種程序員腋逆,我們需要根據(jù)其技能增加code的重載方法;每次增加一種語言,我們需要相應(yīng)地?cái)U(kuò)充使用它的程序員的相關(guān)方法侈贷。ade惩歉,殺一個(gè)產(chǎn)品經(jīng)理祭天,這么頻繁變態(tài)的需求。
貫徹依賴倒置的原則撑蚌,解決方案應(yīng)該是這樣的:
ICoder.java 程序員接口
public interface ICoder {
public void code(ILang iLang);
}
ILang.java 語言接口
public interface ILang {
void runWithSyntax();
}
CoderA.java A類型程序員
public class CoderA implements ICoder {
@Override
public void code(ILang iLang) {
iLang.runWithSyntax();
}
}
Java.java java語言
public class Java implements ILang {
@Override
public void runWithSyntax() {
System.out.println("程序以Java的語法運(yùn)行");
}
}
Lisp.java lisp語言
public class Lisp implements ILang {
@Override
public void runWithSyntax() {
System.out.println("程序以Lisp的語法運(yùn)行");
}
}
Client.java 業(yè)務(wù)場景類
public class Client {
public static void main(String[] args) {
ICoder coder = new CoderA();
ILang lang = new Java();
coder.code(lang);
}
}
這樣的解決方案的好處是:當(dāng)新增低層模塊時(shí)上遥,不需要修改與其平行的模塊,只需要修改業(yè)務(wù)場景類争涌,即高層模塊即可露该,更利于拓展系統(tǒng)。
上面的代碼里面新增Lisp類以后第煮,直接在Client類里面使用ILang lang = new Lisp();即可解幼,程序員就能使用Lisp的語法進(jìn)行編程了。避免去修改程序員類的相關(guān)方法包警。程序應(yīng)該是面向拓展的而不是面向修改的撵摆。
依賴傳遞的三種方法
- 通過構(gòu)造方法傳遞
在需要注入接口的類中聲明接口,然后通過構(gòu)造方法的參數(shù)初始化害晦。在調(diào)用的時(shí)候直接傳入一個(gè)接口的實(shí)現(xiàn)類即可特铝。 - Setter方法傳遞
和構(gòu)造方法注入相似。 - 接口注入
形同這樣的方式是接口注入: ILang lang = new Java();
晚安各位R嘉痢v杲恕!