1. 程式人生 > >嘻哈說:設計模式之依賴倒置原則

嘻哈說:設計模式之依賴倒置原則

嘻哈說-設計模式

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方法構造方法介面方法可以將依賴做個配置
依賴倒置原則就是這麼回事
抽象不依賴細節 細節依賴抽象
高層不依賴低層 都應該依賴抽象
面向介面程式設計記住這點才能在程式碼路走的夠長
易擴充套件易維護風險降低增加開發速度
就像番茄課堂一樣酷

閒來無事聽聽曲,知識已填腦中去;

學習複習新方式,頭戴耳機不小覷。

番茄課堂,學習也要酷。

更多精彩課程,請關注番茄課堂公眾號。

番茄課堂公眾號