1、定義
按照慣例,首先我們來看一下依賴倒置原則的定義。
抽象不應該依賴於細節,細節應當依賴於抽象。 換言之,要針對介面程式設計,而不是針對實現程式設計。
為什麼要這樣說呢?
因為細節具有易變性,非常的不穩定。很多時候,需求改變就會給細節帶來改變。
而抽象則是相對穩定的,抽象是從眾多的事物中抽取出共同的、本質性的特徵,是比較難被改變的。
所以,我們肯定要選擇對抽象程式設計,而不選擇對細節程式設計。
抽象在Java中則指的是抽象類或者介面;細節則是代表著具體實現。
對介面程式設計,是寫出健壯性程式碼的根本,是優秀程式設計師必備的基本素質。
2、含義
1、高層模組不應該依賴低層模組,兩者都應該依賴其抽象
無論是高層模組,還是低層模組,全部都屬於具體的實現,屬於細節,而細節肯定是不能相互依賴的。
他們都應該依賴於抽象。
2、抽象不應該依賴細節
都不應該依賴於細節,特別是抽象更加不應該依賴細節。
3、細節應該依賴抽象
都應該依賴抽象,細節依賴抽象,抽象也依賴抽象。
3、程式碼
1、介面方法中宣告依賴物件
package com.fanqiekt.principle.inversion;
/**
* 廚師介面
*
* @author 番茄課堂-懶人
*/
public interface IChef {
/**
* 做飯
*/
void cooking();
}
複製程式碼
廚師都會做飯。
package com.fanqiekt.principle.inversion;
/**
* 四川廚師
*
* @author 番茄課堂-懶人
*/
public class SiChuanChef implements IChef {
@Override
public void cooking() {
System.out.println("四川廚師做飯,多放辣椒。");
}
}
複製程式碼
廚師的實現類,川菜廚師,其中的邏輯都屬於細節,例如川菜廚師有自己做飯的套路(不能沒有辣)。
package com.fanqiekt.principle.inversion;
/**
* 山東廚師
*
* @author 番茄課堂-懶人
*/
public class ShanDongChef implements IChef {
@Override
public void cooking() {
System.out.println("山東廚師做飯,用蔥薑蒜。");
}
}
複製程式碼
另一個廚師的實現類,魯系廚師,魯菜廚師也有自己做飯的套路(善用蔥薑蒜)。
package com.fanqiekt.principle.inversion;
public interface IWaiter {
/**
* 點餐
* @param chef 指定做飯的菜系廚師
*/
void order(IChef chef);
}
複製程式碼
服務員的抽象介面,服務員都需要為客人點餐。
order(IChef chef) 方法就是介面方法中宣告依賴物件。
在介面中定義該方法,並將依賴的抽象物件作為引數傳入。
package com.fanqiekt.principle.inversion;
/**
* 介面方法中宣告依賴物件
*
* @author 番茄課堂-懶人
*/
public class Waiter implements IWaiter{
@Override
public void order(IChef chef){
if(chef!=null) {
chef.cooking();
}
}
}
複製程式碼
服務員的實現類,點餐是讓傳入的廚師去做飯。
IChef sichuanChef = new SiChuanChef();
IChef shandongChef = new ShanDongChef();
IWaiter waiter = new Waiter();
waiter.order(sichuanChef);
waiter.order(shandongChef);
複製程式碼
將抽象物件作為order方法引數。
四川廚師做飯
山東廚師做飯
複製程式碼
執行結果。
每次呼叫方法時,都傳入依賴物件。
優點是靈活,每次都可以傳入不同的依賴物件。
缺點是繁瑣,每次都需要傳入依賴物件。
2、構造方法傳遞依賴物件
package com.fanqiekt.principle.inversion;
public interface IWaiter {
/**
* 點餐
*/
void cooking();
}
複製程式碼
服務員介面修改:cooking方法去掉引數。
package com.fanqiekt.principle.inversion;
/**
* 構造方法傳遞依賴物件
*
* @author 番茄課堂-懶人
*/
public class Waiter implements IWaiter {
private IChef chef;
/**
* 構造方法中傳入依賴的抽象物件
* @param chef 廚師抽象介面
*/
public Waiter(IChef chef){
this.chef = chef;
}
@Override
public void cooking(){
if(chef!=null) {
chef.cooking();
}
}
}
複製程式碼
通過構造方法傳入依賴的抽象物件。
Waiter waiter1 = new Waiter(sichuanChef);
waiter1.cooking();
Waiter waiter2 = new Waiter(shandongChef);
waiter2.cooking();
複製程式碼
執行看一下結果。
四川廚師做飯
山東廚師做飯
複製程式碼
首次建立的時候就確定了依賴,既是優點又是缺點。
優點是避免了被修改。
缺點是更換依賴,就需要重新再建立物件了。
3、Setter方法傳遞依賴物件
package com.fanqiekt.principle.inversion;
/**
* Setter方法傳遞依賴物件
*
* @author 番茄課堂-懶人
*/
public class Waiter implements IWaiter {
private IChef chef;
public void setChef(IChef chef){
this.chef = chef;
}
@Override
public void cooking(){
if(chef!=null) {
chef.cooking();
}
}
}
複製程式碼
通過set方法賦值依賴物件。
Waiter plan = new Waiter();
plan.setChef(sichuanChef);
plan.cooking();
plan.setChef(shandongChef);
plan.cooking();
複製程式碼
執行看一下結果。
四川廚師做飯
山東廚師做飯
複製程式碼
Setter既可以更換依賴物件,也不用每次呼叫方法時都傳入依賴物件。
3、優點
我們來總結一下依賴倒置原則的幾個優點。
降低風險 依賴抽象,大大提高程式碼的健壯性,風險自然而然就被降低了。
易維護易擴充套件 依賴抽象,才會有框架,基於框架,擴充套件會更方便,維護起來也更省事。
增加開發速度 定好抽象結構就可以並行開發了,而不用過多的被他人的進度干預。
4、嘻哈說
接下來,請您欣賞依賴倒置原則的原創歌曲。
嘻哈說:依賴倒置原則
作曲:懶人
作詞:懶人
Rapper:懶人
需要依賴廚師為我做頓美食
不用管他到底川系或者徽系
只依賴廚師介面做法多麼美麗
不然修改起來牽扯太多的話是多麼費事
set方法構造方法介面方法可以將依賴做個配置
依賴倒置原則就是這麼回事
抽象不依賴細節 細節依賴抽象
高層不依賴低層 都應該依賴抽象
面向介面程式設計記住這點才能在程式碼路走的夠長
易擴充套件易維護風險降低增加開發速度
就像番茄課堂一樣酷
複製程式碼
閒來無事聽聽曲,知識已填腦中去;
學習複習新方式,頭戴耳機不小覷。
番茄課堂,學習也要酷。