剖析DI

0x00.前言

當(dāng)我們研究一些晦澀的源碼,上網(wǎng)查閱資料的時(shí)候,映入眼簾的總有這么些名詞:DIP、IOC、DI、DL、IOC容器這些專業(yè)名詞。如果不懂這些名詞背后的含義,我們內(nèi)心有可能是這樣的:

image

0x01.小例子

/**
 * 餐廳類
 */
public class Restaurant {

    //后臺收銀系統(tǒng)
    private WeChatPay pay = new WeChatPay();

    //收款操作
    public void transact(double money) {
        pay.receiveMoney(money);
    }
}

import java.util.Date;

/**
 * 微信
 */
public class WeChatPay {
    public void receiveMoney(double money) {
        System.out.println(new Date() + ",已用微信收款:" + money + "元");
    }
}

image
這時(shí)候Restaurant類就依賴于WeChatPay,兩個(gè)類產(chǎn)生依賴

0x02.DIP

DIP的英文名:Dependency Inversion Principle,中文名:依賴倒轉(zhuǎn)原則

定義:

  • High-level modules should not depend on low-level modules. Both should depend on abstractions

  • Abstractions should not depend on details. Details should depend on abstractions

理解:

  • 高層模塊不應(yīng)該直接依賴于底層模塊的具體實(shí)現(xiàn),而應(yīng)該依賴于底層的抽象。換言之,模塊間的依賴是通過抽象發(fā)生,實(shí)現(xiàn)類之間的不發(fā)生直接依賴關(guān)系,其依賴關(guān)系是通過接口或抽象類產(chǎn)生的

  • 面向接口編程

它僅僅是面向?qū)ο筌浖O(shè)計(jì)的一種原則。它僅僅告訴你兩個(gè)模塊之間如何協(xié)調(diào)依賴關(guān)系,但是并沒有告訴你如何做!

舉個(gè)例子

我們經(jīng)常所說的三層架構(gòu)(UI、BLL、DAL)

image

image

圖二的版本,就是高層模塊依賴于低層模塊的抽象,就好像依賴“倒置”。這樣可以使得整體的架構(gòu)更加的穩(wěn)定,靈活,及自如的面對需求的變化。

0x03.IOC

  • IOC的英文名:Inversion Of Control ,中文名:控制反轉(zhuǎn)
  • IOC基于DIP原則上的實(shí)現(xiàn)的是一種軟件設(shè)計(jì)模式,它告訴你應(yīng)該如何做,來解除相互依賴模塊的耦合。它為相互依賴的組件提供抽象,將依賴對象的獲得交給第三方來控制,即依賴對象不在被依賴的類中直接通過new來獲取。
  • IOC的實(shí)現(xiàn)的方式一般有兩種,依賴注入和依賴查找。一般DI使用的比較多

0x04.DI

  • DI的英文名:Dependency Injection,中文名稱:依賴注入。
  • DI就是將依賴對象的創(chuàng)建和綁定轉(zhuǎn)移到被依賴對象類的外部來實(shí)現(xiàn)。它提供是一種機(jī)制,將需要依賴(低層模塊)對象的引用傳遞給被依賴(高層模塊)對象。

DI注入有三種方式

  • 構(gòu)造函數(shù)注入
  • 屬性注入
  • 接口注入

Demo講解

/**
 * di Ipay 接口
 */
public interface IPay {
    void receiveMoney(double money);
}

/**
 * 重構(gòu)后的微信支付
 */
public class WebChatPay implements IPay {
    public void receiveMoney(double money) {
        Date now = new Date();
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println(format.format(now) + ",已用重構(gòu)后的微信收款:" + money + "元");
    }
}
/**
 * 重構(gòu)后的餐廳類構(gòu)造器注入
 */
public class Restaurant {

    private IPay _pay;

    public Restaurant(IPay pay) {
        this._pay = pay;
    }

    //收款操作
    public void transact(double money) {
        _pay.receiveMoney(money);
    }
}

0x01.構(gòu)造器注入

System.out.println("==========通過構(gòu)造函數(shù)注入開始==============");
IPay pay = new WebChatPay();//在外部創(chuàng)建依賴對象
Restaurant restaurant = new Restaurant(pay);
restaurant.transact(10);
System.out.println("==========通過構(gòu)造函數(shù)注入結(jié)束==============");
image

這時(shí)候我們就看到Restaurant將依賴的WeChatPay對象的創(chuàng)建和綁定轉(zhuǎn)移到Restaurant類外部來實(shí)現(xiàn)了。這樣就解除了Restaurant類與WeChatPay類的耦合關(guān)系。如果將支付方式改成Alipay,只需要定義一個(gè)Alipay類,然后在外部重新綁定依賴。不需要修改Restaurant類。

0x02.屬性注入

System.out.println("==========通過屬性注入開始==============");
IPay paySetter = new WebChatPay();
RestaurantBySetter restaurantSetter = new RestaurantBySetter();
restaurantSetter.setPay(paySetter);
restaurantSetter.transact(10);
System.out.println("==========通過屬性注入結(jié)束==============");
image

0x03.接口注入

System.out.println("==========通過接口注入開始==============");
IPay payInterface = new WebChatPay();
RestaurantByInterface restaurantInterface = new RestaurantByInterface();
restaurantInterface.extraInstance(payInterface);
restaurantInterface.transact(10);
System.out.println("==========通過接口注入結(jié)束==============");
image

0x05.IOC容器

DI框架,用來自動(dòng)創(chuàng)建、維護(hù)依賴對象,并管理其生命周期。

常使用的IOC容器有:
Net:Ninject、Spring.NET、Unity、Autofac等
Java:Spring等

0x06.總結(jié)

IOC帶來好處:

  • 降低了各個(gè)組件之間的耦合性,增強(qiáng)了內(nèi)聚性。
  • 大中型項(xiàng)目,團(tuán)隊(duì)分工明確,職責(zé)明確,便于測試
  • 使得模塊具有熱插拔特性,增加了模塊的復(fù)用性
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容