參考慕課網視訊《Java設計模式精講》:
視訊作者:Geely
視訊連結:https://coding.imooc.com/lesson/270.html#mid=17149
定義
高層子產品不應該依賴低層子產品,二者都應該依賴其抽象。
強調
抽象不應該依賴細節,細節應該依賴抽象。
針對接口程式設計,不要針對實作程式設計。
優點
可以減少類間的耦合性、提高系統穩定性,提高代碼可讀性和可維護性,可降低修改程式所造成的風險。
案例:清風先生通過看Java視訊來提升自己。
public class JavaVideo {
//播放的功能
public void play(){
System.out.println("看java的視訊");
}
}
public class MrQingFeng {
//看視訊
public void watch(JavaVideo video){
video.play();
}
}
清風先生具有看的功能,并且依賴于JavaVideo這個類。接下來寫測試類。
public class MainTest {
@Test
public void testMethod1(){
MrQingFeng mrQingFeng = new MrQingFeng();
JavaVideo video = new JavaVideo();
mrQingFeng.watch(video);
}
}
這段代碼很簡單,結果就是:清風先生通過看Java視訊,成功的提升了自己的Java水準。但是,技術更新疊代很快,現在已經是人工智能和大資料的時代了。是以,清風先生想要開始學習Python這門語言。他還是更加傾向于視訊學習。是以,清風先生想要看Python視訊。但是呢,清風先生家裡的播放器隻支援Java格式的視訊。不支援Python格式的。是以,沒辦法,他就放棄了。
上面的例子,就說明了,清風這個類是個高層子產品,Java視訊是一個低層子產品。他依賴于具體的實作。如果需要看HTML、GO或者其他的視訊,就要更改他所依賴的具體實作。這樣耦合度很大,生産力很低,當需求變更的時候,就要面臨大面積的重構。
是以,下面通過抽象,來解決這個問題。
案例:清風先生想要學習一門程式設計語言,大家都推薦他通過看書來學習,但是他卻不知道應該買什麼書。是以呢,我們就來幫幫他。
定義一個買書的接口:
package com.qfcwx.dependencyinversion;
/**
* @ClassName: Book
* @Author: 清風一陣吹我心
* @Description: TODO 一個買書的接口
* @Date: 2019/4/7 17:30
* @Version 1.0
**/
public interface Book {
/**
* 買書
*/
void buyBook();
}
他在B公司的朋友,推薦他買Java的書來學習,因為Java的生态圈已經很完善了。是以,就要定一個類來實作上面的接口。
public class JavaBook implements Book {
@Override
public void buyBook() {
System.out.println("買了一本java語言的書");
}
}
而他在A公司的朋友說現在容器化技術,區塊鍊這麼火。是以推薦他去學習GO語言,他又計劃買GO語言的書。
public class GoBook implements Book {
@Override
public void buyBook() {
System.out.println("買了一本go語言的書");
}
}
人生苦短,我用Python。誰知道,在T公司的女朋友來信了,說現在Python這麼火,不選擇它,還去選别的,是不是今晚想跪鍵盤了?
面對三方面的支援,清風先生可謂舉棋不定啊。沒關系,我們來幫他定。
public class MrQingFeng {
private Book book;
public void setBook(Book book) {
this.book = book;
}
//買各種書的方法
public void buyKindOfBook() {
book.buyBook();
}
}
想成為一名程式猿,成為一名優秀的程式猿,光掌握一本語言是不夠的,要養成終身學習的習慣。是以,建議清風先生,把每種語言的書都買上,這樣也能解決你現在的糾結情緒,還不用跪鍵盤了。豈不是美哉?
public class MainTest {
public static void main(String[] args) {
MrQingFeng mrQingFeng = new MrQingFeng();
mrQingFeng.setBook(new JavaBook());
mrQingFeng.buyKindOfBook();
mrQingFeng.setBook(new PythonBook());
mrQingFeng.buyKindOfBook();
mrQingFeng.setBook(new GoBook());
mrQingFeng.buyKindOfBook();
}
}
看吧,通過依賴抽象的方式,幫清風先生解決了買書的困難。瞬間覺得自己很偉大呢。
言歸正傳,上面的例子,就是強調,我們要面向接口程式設計,不要針對其實作程式設計。若想擴充具體的實作,隻需要實作接口,或者繼承其抽象即可。
例如:清風先生又想買Netty、SpringBoot的書。當然沒問題,隻需要實作買書的接口就行了。不會對應用的整體架構造成影響。
知識擴充
因為清風先生依賴書這個接口,是以,需要将其注入。這裡的注入方式,使用的是Setter方式。
當然還有構造器注入、接口方法注入。
構造器注入
private Book book;
public MrQingFeng(Book book){
this.book = book;
}
public void buyKindOfBook() {
book.buyBook();
}
接口方法
public void buyKindOfBook(Book book) {
book.buyBook();
}
上面說了三種接口注入的方式,在Spring中最常用的就是Setter和構造器注入,也推薦大家使用這兩種方式。
即使想活成強人,也得一步步來不是,别太苦了自己,負面情緒多了就找人宣洩一下,青春加油,未來加油!