亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

深入理解依賴注入

e10101 / 1392人閱讀

摘要:上面這部分代碼不變,還是通過(guò)在構(gòu)造器中傳入依賴的方式初始化依賴調(diào)用這里,調(diào)用方無(wú)需了解內(nèi)部對(duì)的依賴。而配置一般用于上自動(dòng)掃描并注入的代碼如下這里只給出直接在依賴對(duì)象上添加注解的形式,還可以通過(guò)構(gòu)造器和注入依賴,這里就不多說(shuō)了。

前言

相信所有面試java開發(fā)的童鞋一定都被問(wèn)到過(guò)是否使用過(guò)Spring,是否了解其IOC容器,為什么不直接使用工廠模式,以及究竟IOC和DI區(qū)別在于哪里這種問(wèn)題。今天就結(jié)合JAVA語(yǔ)言,解釋一下究竟是如何衍生出DI模式,以及其在Spring中的實(shí)現(xiàn)。

很久很久以前

初學(xué)Java,我們一定會(huì)學(xué)到面向?qū)ο蟮木幊趟枷?,以及使用new關(guān)鍵字新建一個(gè)對(duì)象。假設(shè)現(xiàn)在有一個(gè)郵件發(fā)送系統(tǒng),該系統(tǒng)包含拼寫檢查功能。那么本著面向?qū)ο蟮乃枷胍约瓣P(guān)注點(diǎn)分離的思想,我們會(huì)將其分解為兩個(gè)類:EmailerSpellChecker。其中,Emailer依賴著SpellChecker提供的服務(wù),這兩個(gè)類的實(shí)現(xiàn)如下:

public class SpellChecker{
    ...
    public void check(){
       ...
    }
}

public class Emailer{
    private SpellChecker spellChecker;
    public Emailer(){
        spellChecker = new SpellChecker();
    }
}

可以看到我們?cè)跇?gòu)造器中使用new新建了一個(gè)SpellChecker的對(duì)象。

現(xiàn)在我們來(lái)分析一下這個(gè)實(shí)現(xiàn)的不足之處:

可測(cè)試性:假設(shè)現(xiàn)在我希望測(cè)試Emailer的功能是否完善,但是此時(shí)SpellChecker并沒有完成開發(fā)與測(cè)試,那么我們將無(wú)法對(duì)Emailer進(jìn)行測(cè)試。就算SpellChecker已經(jīng)開發(fā)完成,但是我們也無(wú)法排除當(dāng)前的錯(cuò)誤是否和SpellChecker的實(shí)現(xiàn)無(wú)關(guān)。

可維護(hù)性:假設(shè)現(xiàn)在支持多語(yǔ)種,那么我需要分別實(shí)現(xiàn)一個(gè)EnglishEmailer和FrenchEmailer類。他們的構(gòu)造函數(shù)中分別初始化EnglishSpellChecker和FrenchSpellChecker。以后每增加一個(gè)語(yǔ)種都需要新建一個(gè)新的Emailer類。而這些類的代碼本質(zhì)上都是重復(fù)的。更不要提假設(shè)里面

因此我們就需要一種新的初始化依賴的方式。

自己初始化不行,那你給我一個(gè)現(xiàn)成的吧!

既然在調(diào)用依賴的類中初始化依賴這么麻煩,不如將構(gòu)建完成的依賴傳入調(diào)用的類。

public class SpellChecker{
    ...
    public void check(){
       ...
    }
}

public class Emailer{
    private SpellChecker spellChecker;
    public Emailer(SpellChecker spellChecker){
        this.spellChecker = spellChecker;
    }
}
//使用
Emailer email = new Emailer(new EnglishSpellChecker())

從測(cè)試性的角度來(lái)說(shuō),這個(gè)代碼明顯更加易于測(cè)試了,我們可以提供SpellChecker的一個(gè)Mock實(shí)現(xiàn),如Emailer e = new Emailer(new MockSpellChecker())來(lái)對(duì)Emailer進(jìn)行測(cè)試。那么這種實(shí)現(xiàn)的缺點(diǎn)在哪里呢?

首先,調(diào)用Emailer的代碼需要知道如何去初始化SpellChecker,而這明顯暴露了Emailer的內(nèi)部實(shí)現(xiàn),違背了信息隱藏的思想。其次,一旦依賴發(fā)生變化,比如Emailer還需要依賴一個(gè)定時(shí)裝置Scheduler來(lái)實(shí)現(xiàn)定時(shí)發(fā)送郵件,那么所有的調(diào)用Emailer的代碼都需要發(fā)生改變。顯然,這種寫法的可維護(hù)性依然不高。

工廠模式閃亮登場(chǎng),所有的初始化都交給我了!

那么,我們是否可以將所有對(duì)象構(gòu)建的代碼提取出來(lái),像工廠標(biāo)準(zhǔn)件一樣生產(chǎn)出來(lái)。所有對(duì)對(duì)象的調(diào)用都通過(guò)工廠提供。

public class SpellChecker{
    ...
    public void check(){
       ...
    }
}

public class Emailer{
    private SpellChecker spellChecker;
    public Emailer(SpellChecker spellChecker){
        this.spellChecker = spellChecker;
    }
}
//上面這部分代碼不變,還是通過(guò)在構(gòu)造器中傳入依賴的方式初始化依賴

public class EmailerFactory {
    public Emailer newFrenchEmailer(){
        return new Emailer(new FrenchSpellChecker());
    }
}

//調(diào)用
Emailer email = new EmailerFactory().newFrenchEmailer();

這里,調(diào)用方無(wú)需了解內(nèi)部對(duì)SpellChecker的依賴。無(wú)論之后Emailer的依賴發(fā)生什么樣的變化,客戶端代碼都不會(huì)受到影響。那么這種設(shè)計(jì)有沒有缺陷呢?

當(dāng)然是有的。Emailer的測(cè)試和之前一樣,我們可以通過(guò)傳入Mock的對(duì)象來(lái)對(duì)其進(jìn)行測(cè)試。那么調(diào)用Emailer的服務(wù)怎么辦呀?在調(diào)用方看來(lái)我們只是依賴著Factory對(duì)象,因此我們需要通過(guò)定義Factory返回一個(gè)Mock對(duì)象才行,同時(shí)這個(gè)對(duì)象還不能影響真正的Factory的實(shí)現(xiàn)。

除此以外,每當(dāng)我們對(duì)一個(gè)新的語(yǔ)種添加支持時(shí),我們都必須添加一段新的代碼,如下:

public class EmailerFactory {
    public Emailer newJapaneseEmailer() {
        Emailer service = new Emailer();
        service.setSpellChecker(new JapaneseSpellChecker());
        return service;
    }
    public Emailer newFrenchEmailer() {
        Emailer service = new Emailer();
        service.setSpellChecker(new FrenchSpellChecker());
        return service;
    } 
}

而這兩段初始化代碼基本上是完全相同的!而假設(shè)以后我們需要實(shí)現(xiàn)一個(gè)全球通用版本。。。
光是無(wú)聊的工廠模式代碼就要花費(fèi)我們大量的時(shí)間!

我說(shuō)出你的名字,你敢應(yīng)嗎!

有沒有這樣一個(gè)東西,客戶端代碼報(bào)出它的編號(hào)key,它就會(huì)返回那個(gè)對(duì)象的實(shí)例。當(dāng)然這個(gè)實(shí)例是根據(jù)配置生成的。比如Emailer English這樣的key,就會(huì)返回英語(yǔ)的Emailer。這種思路衍生出了服務(wù)定位模式。這個(gè)模式相當(dāng)于站在了所有工廠模式的最前端。它就像是一個(gè)老式的電話中轉(zhuǎn)服務(wù),調(diào)用服務(wù)的人輸入服務(wù)的唯一編號(hào),即電話號(hào)碼,而服務(wù)定位器找到該服務(wù)并返回該服務(wù)的實(shí)例。調(diào)用如下:

Emailer emailer = (Emailer) new ServiceLocator().get("Emailer");

JNDI(Java Naming and Directory Interface)就是該思想下的一個(gè)實(shí)現(xiàn)。服務(wù)的提供方在JNDI上注冊(cè)服務(wù),之后調(diào)用方在JNDI上檢索服務(wù),實(shí)現(xiàn)二者之間的解耦。

這個(gè)模式的問(wèn)題和工廠模式類似,難以測(cè)試以及需要管理共享狀態(tài)。其次,通過(guò)使用String類型的Key來(lái)獲取服務(wù)無(wú)法在編譯時(shí)對(duì)服務(wù)調(diào)用是否正確以及服務(wù)類型是否正確進(jìn)行檢查。

這里將不會(huì)給出JNDI的具體實(shí)現(xiàn),對(duì)JNDI的概念有困惑的可以查看這篇文章

Injector隆重登場(chǎng)

看來(lái),任何和構(gòu)造對(duì)象相關(guān)的代碼夾雜在業(yè)務(wù)代碼中都會(huì)帶來(lái)麻煩,那么我們可以將這部分代碼全權(quán)委托給構(gòu)造框架,業(yè)務(wù)代碼通過(guò)依賴注入從而關(guān)注于業(yè)務(wù)本身,而框架可以通過(guò)配置甚至是自動(dòng)的生成對(duì)象注入到客戶端。從而實(shí)現(xiàn)二者的完全解耦。

至此,對(duì)象關(guān)聯(lián)圖的構(gòu)造,聯(lián)系和組裝將和業(yè)務(wù)代碼完全無(wú)關(guān),這種情況也被成為控制反轉(zhuǎn)(IOC)

不同的框架對(duì)于依賴注入的實(shí)現(xiàn)是不同的,但是本質(zhì)上來(lái)說(shuō),他們都確保了客戶端無(wú)需在業(yè)務(wù)代碼中了解注入的依賴是如何初始化的。

IOC vs DI

那么IOC和DI之間的區(qū)別究竟是什么呢?
IOC這個(gè)概念所表示的領(lǐng)域其實(shí)超出了依賴注入的范圍,它更多強(qiáng)調(diào)的是控制反轉(zhuǎn),也就是說(shuō),這個(gè)對(duì)象是別人替你創(chuàng)建好的。因此DI是IOC的一種實(shí)現(xiàn)機(jī)制。而控制反轉(zhuǎn)可以運(yùn)用于更多的場(chǎng)景,如:

J2EE應(yīng)用服務(wù)器中的一個(gè)模塊,比如Servlet

框架自動(dòng)調(diào)用的測(cè)試方法

點(diǎn)擊鼠標(biāo)后調(diào)用的事件處理器

IOC不僅負(fù)責(zé)創(chuàng)建對(duì)象,還需要管理對(duì)象的生命周期。不同的生命周期需要觸發(fā)不同的調(diào)用,這些調(diào)用被稱為回調(diào)函數(shù)。除此以外,IOC容器管理的對(duì)象需要被打上標(biāo)記,比如使用@Autowire,@Component注解的類和對(duì)象,以及繼承了Servlet接口的Servlet才會(huì)被Servlet容器管理。

因此我們常見的Spring更像是將IOC和DI思想結(jié)合在一起生成的產(chǎn)物。

更多關(guān)于IOC VS DI可以參考這篇文章

Spring

Spring是一個(gè)輕量級(jí)的依賴注入框架,它已經(jīng)成了所有JAVA開發(fā)者無(wú)法躲開的開發(fā)大禮包。Spring提供了三種依賴注入的方式:XML,注解和Java Config

XML方式曾經(jīng)非常流行,但是這種方式也逐漸暴露出問(wèn)題,主要的問(wèn)題在于無(wú)法對(duì)注入的依賴進(jìn)行類型檢查,從而導(dǎo)致代碼無(wú)法在編譯期間識(shí)別出問(wèn)題,只能在運(yùn)行期間拋出異?!,F(xiàn)在主要推薦自動(dòng)掃描并注入以及通過(guò)JavaConfig代碼來(lái)配置。而XML配置一般用于Legacy System上

Autowired

自動(dòng)掃描并注入的代碼如下:

public class Emailer{
    @Autowired
    private SpellChecker spellChecker;

    public class Emailer(SpellChecker spellChecker){
    }    
}

@Component
public class SpellChecker{
    ...
}

@ComponentScan
public class EmailerConfig{
}

這里只給出直接在依賴對(duì)象上添加注解的形式,還可以通過(guò)構(gòu)造器和setter注入依賴,這里就不多說(shuō)了。

Java Config

Java Config則是將配置代碼多帶帶提取出來(lái):

@Configuration
public class EmailerConfig{
    @Bean
    public Emailer EnglishEmailer(){
        return new Emailer(new EnglishSpellChecker());
    }
}

當(dāng)然,這里也可以通過(guò)依賴注入的方式來(lái)確保傳入的對(duì)象是單例的(默認(rèn)情況下Spring生成的對(duì)象為單例)

@Configuration
public class EmailerConfig{
    @Bean
    public Emailer EnglishEmailer(SpellChecker spellChecker){
        return new Emailer(spellChecker);
    }
}


想要了解更多開發(fā)技術(shù),面試教程以及互聯(lián)網(wǎng)公司內(nèi)推,歡迎關(guān)注我的微信公眾號(hào)!將會(huì)不定期的發(fā)放福利哦~

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/69658.html

相關(guān)文章

  • 深入理解IoC(控制反轉(zhuǎn))、DI(依賴注入

    摘要:引述最近看設(shè)計(jì)模式以及代碼,對(duì)于控制反轉(zhuǎn)以及依賴注入這些概念非常困惑,于是找了一些資料,以下是對(duì)于控制反轉(zhuǎn)的一下理解。其中最常見的方式叫做依賴注入,簡(jiǎn)稱,還有一種方式叫依賴查找。在軟件工程中,依賴注入是種實(shí)現(xiàn)控制反轉(zhuǎn)用于解決依賴性設(shè)計(jì)模式。 引述 最近看設(shè)計(jì)模式以及l(fā)aravel代碼,對(duì)于控制反轉(zhuǎn)以及依賴注入這些概念非常困惑,于是找了一些資料,以下是對(duì)于控制反轉(zhuǎn)的一下理解。 概念 Io...

    xcc3641 評(píng)論0 收藏0
  • 深入剖析 Laravel 服務(wù)容器

    摘要:劃下重點(diǎn),服務(wù)容器是用于管理類的依賴和執(zhí)行依賴注入的工具。類的實(shí)例化及其依賴的注入,完全由服務(wù)容器自動(dòng)的去完成。 本文首發(fā)于 深入剖析 Laravel 服務(wù)容器,轉(zhuǎn)載請(qǐng)注明出處。喜歡的朋友不要吝嗇你們的贊同,謝謝。 之前在 深度挖掘 Laravel 生命周期 一文中,我們有去探究 Laravel 究竟是如何接收 HTTP 請(qǐng)求,又是如何生成響應(yīng)并最終呈現(xiàn)給用戶的工作原理。 本章將帶領(lǐng)大...

    abson 評(píng)論0 收藏0
  • Laravel深入學(xué)習(xí)1 - 依賴注入

    摘要:然而,我們需要注意的是僅是軟件設(shè)計(jì)模式依賴注入的一種便利的實(shí)現(xiàn)形式。容器本身不是依賴注入的必要條件,在框架他只是讓其變得更加簡(jiǎn)便。首先,讓我們探索下為什么依賴注入是有益的。繼續(xù)深入讓我們通過(guò)另一個(gè)示例來(lái)加深對(duì)依賴注入的理解。 聲明:本文并非博主原創(chuàng),而是來(lái)自對(duì)《Laravel 4 From Apprentice to Artisan》閱讀的翻譯和理解,當(dāng)然也不是原汁原味的翻譯,能保證9...

    sunsmell 評(píng)論0 收藏0
  • 深入理解控制反轉(zhuǎn)(IoC)和依賴注入(DI)

    摘要:本文一大半內(nèi)容都是通過(guò)舉例來(lái)讓讀者去理解什么是控制反轉(zhuǎn)和依賴注入,通過(guò)理解這些概念,來(lái)更加深入。這種由外部負(fù)責(zé)其依賴需求的行為,我們可以稱其為控制反轉(zhuǎn)。工廠模式,依賴轉(zhuǎn)移當(dāng)然,實(shí)現(xiàn)控制反轉(zhuǎn)的方法有幾種。 容器,字面上理解就是裝東西的東西。常見的變量、對(duì)象屬性等都可以算是容器。一個(gè)容器能夠裝什么,全部取決于你對(duì)該容器的定義。當(dāng)然,有這樣一種容器,它存放的不是文本、數(shù)值,而是對(duì)象、對(duì)象的描...

    HollisChuang 評(píng)論0 收藏0
  • Laravel深入學(xué)習(xí)2 - 控制反轉(zhuǎn)容器

    摘要:控制反轉(zhuǎn)容器控制反轉(zhuǎn)使依賴注入變得更加便捷。有瑕疵控制反轉(zhuǎn)容器是實(shí)現(xiàn)的控制翻轉(zhuǎn)容器的一種替代方案。容器的獨(dú)立使用即使沒有使用框架,我們?nèi)匀豢梢栽陧?xiàng)目中使用安裝組件來(lái)使用的控制反轉(zhuǎn)容器。在沒有給定任何信息的情況下,容器是無(wú)法實(shí)例化相關(guān)依賴的。 聲明:本文并非博主原創(chuàng),而是來(lái)自對(duì)《Laravel 4 From Apprentice to Artisan》閱讀的翻譯和理解,當(dāng)然也不是原汁原味...

    worldligang 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<