淺談angular2中的依賴注入

引言

依賴注入恰响,有后端背景的童鞋(尤其是熟悉java spring框架的)應(yīng)該不會陌生,提到依賴注入沼撕,就不得不說一下控制反轉(zhuǎn)侧啼,因為依賴注入實際上是控制反轉(zhuǎn)概念的一種實現(xiàn)模式。

控制反轉(zhuǎn)(inversion of control泪蔫,IoC)原則的非正式稱謂是“好萊塢法則”棒旗,它來自好萊塢的一句常用語“別打給我們,我們會打給你(don't call us, we'll call you)”撩荣,從控制權(quán)的角度來看铣揉,控制權(quán)從我被反轉(zhuǎn)到了別人,我從打電話這個行為的發(fā)出者餐曹,變成了打電話這個行為的接受者逛拱。

控制“正”轉(zhuǎn)可以理解為面向過程編程,定義一個main函數(shù)台猴,在main函數(shù)里面定義所有的參與者與他們之間的交互過程朽合,一點不能偷懶。需要用到某個對象某個類饱狂,自己去new旁舰,需要某個庫函數(shù),自己去主動調(diào)用嗡官。

控制“反”轉(zhuǎn)可以理解為面向?qū)ο缶幊碳埽覀冇辛烁鞣N適用于不同場景下的框架和設(shè)計模式,這些事物幫我們搭建好了一個整體架構(gòu)衍腥,這個架構(gòu)用于準備一些基本而普遍需要的基礎(chǔ)物資磺樱。

控制反轉(zhuǎn)的設(shè)計目標

  • 將執(zhí)行任務(wù)這個動作和任務(wù)(具體實現(xiàn))解耦
  • 讓模塊專注于它自己的設(shè)計目標。不需要考慮別的模塊實現(xiàn)了什么婆咸,是如何實現(xiàn)的竹捉,模塊之間依賴于接口
  • 讓符合相同契約的模塊能夠互相替代

遵循控制反轉(zhuǎn)的幾個事物

  • 框架:有些太繁瑣太基礎(chǔ)的事情我已經(jīng)幫你做好了,我做不了的那部分以坑的形式留給你了尚骄,填完坑你的工作也就完成了块差,后邊的事情我來處理
  • 回調(diào)、調(diào)度器倔丈、事件循環(huán):把坑填好憨闰,等到時機成熟我就來和你相會
    策略模式:坑的游戲規(guī)則我已經(jīng)定義好(輸入輸出),你只需要按規(guī)則填坑就好
  • 模板方式模式:坑的種類和踩坑的順序我已定義好需五,你只需要負責(zé)填坑
  • 工廠模式和依賴注入類似鹉动,下面詳細分析

依賴注入

在任何一個有請求作用的系統(tǒng)當(dāng)中,至少需要有兩個類互相配合工作宏邮,在一個入口類下使用new關(guān)鍵字創(chuàng)建另一個類的對象實例泽示,“我”充當(dāng)一個入口類缸血,在這個入口類中,我每次吃飯的時候都要買一雙一次性筷子(每一次使用都要new一次)械筛,在這樣的關(guān)系下捎泻,是“我”(即調(diào)用者)每次都要“主動”去買一次性筷子(另一個類),是我控制了筷子埋哟,在這種控制正轉(zhuǎn)的關(guān)系下族扰,放在現(xiàn)實生活當(dāng)中,肯定是不現(xiàn)實的定欧,而且人是懶惰的,他總會去創(chuàng)造出更加方便自己生活的想法怒竿,更確切的做法是砍鸠,買一雙普通的筷子(非一次性),把他放在一個“框架”當(dāng)中耕驰,你需要使用的時候就對“框架”說:我想要用筷子(向框架發(fā)出請求)爷辱,接著筷子就會"注入"到你的手上,而在這個過程當(dāng)中朦肘,你不再是控制方饭弓,反而演變成一名請求者(雖然本身還是調(diào)用者),依賴于框架給予你資源媒抠,控制權(quán)落到了框架身上弟断,這就是依賴注入的設(shè)計原理。

要理解依賴注入趴生,就必須搞清楚幾個問題:
參與者:都有誰
依賴:誰依賴于誰阀趴,為什么需要依賴
注入:誰注入誰,到底注入什么
控制:誰控制誰苍匆,控制什么

參與者:
一般有三方參與者刘急,參與者1:某個對象,參與者2:DI框架浸踩,參與者3:對象所需的外部資源(類叔汁,文件等等)
依賴:
對象依賴于DI框架
為什么需要依賴:
“對象(參與者1)”需要“DI框架(參與者2)”提供所需的“外部資源(參與者3)”
誰注入誰:
DI框架注入“對象(參與者1)”
注入什么:
注入“對象(參與者1)”所需的“外部資源(參與者3)”
誰控制誰:
“DI框架(參與者2)”控制對象(參與者1)”
控制什么:
主要是控制對象所需外部資源實例的創(chuàng)建,管理所需重要對象的生命周期
反轉(zhuǎn):
在傳統(tǒng)方式下检碗,也就是正向据块,如果部件A需要依賴部件B,那就意味著A在內(nèi)部要創(chuàng)建一個B的實例折剃,也就是A依賴于B瑰钮。在依賴注入機制也就是反向,如果在部件A中用到部件B微驶,我們就應(yīng)該期待B被傳給A

正向

反向

依賴注入:它的作用是讓框架幫你處理重要對象的生命周期的管理浪谴,不需要你顯式地進行管理(對象構(gòu)造和銷毀)
優(yōu)勢:架構(gòu)松耦合开睡,測試更簡單

Angular 依賴注入

在angular中,依賴注入包括三部分

  • 提供商:負責(zé)把一個令牌(可能是字符串也可能是類)映射到一個依賴的列表苟耻,它告訴angular該如何根據(jù)指定的令牌創(chuàng)建對象
  • 注入器:負責(zé)持有一組綁定篇恒,當(dāng)外界要求創(chuàng)建對象時,解析這些依賴并注入它們凶杖。我們不需要創(chuàng)建angular注入器胁艰,angular在啟動過程中會自動為我們創(chuàng)建一個應(yīng)用級注入器(platformBrowserDynamic().bootstrapModule(AppModule)
  • 依賴:被用于注入的對象
注入器的提供商
  1. 類提供商 useClass
    providers: [Logger],這其實是注冊提供商的簡寫表達式智蝠,完整的應(yīng)該是providers: [{provide: Logger,useClass: Logger}]
    provide是令牌腾么,用于定位依賴值和注冊提供商
    useClass是提供商,用于定義對象杈湾,它用來指出注入什么以及如何注入
    某些時候解虱,我們會請求一個不同的類來提供服務(wù):
    providers: [{provide: Logger,useClass: BetterLogger}]
  2. 別名提供商 useExisting
    制造一個別名來引用以前注冊過的令牌,比如:
    某個舊組件依賴一個OldLogger類漆撞,OldLogger和NewLogger具有相同的接口殴泰,但是由于某些原因, 我們不能升級這個舊組件并使用它浮驳。當(dāng)舊組件想使用OldLogger記錄消息時悍汛,我們希望改用NewLogger的單例對象來記錄,不管組件請求的是新的還是舊的日志服務(wù)至会,依賴注入器注入的都應(yīng)該是同一個單例對象离咐。 也就是說,OldLogger應(yīng)該是NewLogger的別名奉件。如果使用useClass應(yīng)用中會有兩個不同的NewLogger實例健霹,這顯然不是我們想看到的,這時候就可以使用useExisting
providers: [
      NewLogger,
      {provide: OldLogger,useClass: NewLogger} //創(chuàng)建NewLogger的兩個實例
]
      NewLogger,
      {provide: OldLogger,useExisting: NewLogger} //只創(chuàng)建NewLogger的一個實例
]
  1. 值提供商 useValue
    當(dāng)我們需要一個常量瓶蚂,而它可能會根據(jù)應(yīng)用的其他部分甚至環(huán)境進行重定義時糖埋,這種方式非常重要。
    官方推薦使用InjectionToken作為令牌
import { InjectionToken } from '@angular/core';
export const TITLE = new InjectionToken <string>('title');
providers:[
       {provide:TITLE, useValue: 'Hero of the Month'}
]
  1. 工廠提供商 useFactory
    使用工廠提供商進行注入窃这,需要寫一個返回任意對象的函數(shù)瞳别,工廠是創(chuàng)建可諸如對象的最強方式,因為我們可以在工廠函數(shù)中“為所欲為”杭攻。
providers:[{
        provide: MyComponent,
        useFactory: ()=> {
            if(loggedIn) {
               return new MyloggedComponent();
            }
            return new MyComponent();
        }
}]
依賴注入令牌

  1. 我們最常用的
    providers: [{provide: Logger,useClass: BetterLogger}]
  2. 類-接口
    使用沒有被繼承的抽象類作為依賴注入令牌祟敛,這種用法的類叫做:類-接口,它的好處是:提供了接口的強類型兆解,能像正常類一樣把它當(dāng)做提供商令牌使用馆铁。類-接口應(yīng)該只定義允許它消費者調(diào)用的成員,窄的接口有助于解耦該類的具體實現(xiàn)和它的消費者锅睛。
    不能使用接口作為依賴注入令牌埠巨,因為在JavaScript中并沒有接口的概念历谍,編譯后angular無法識別
    更詳細內(nèi)容參考angular官方文檔
  3. InjectionToken
    有時候依賴對象并不是一個類,它可能是一個簡單的值辣垒,比如日期望侈,數(shù)字和字符串,或者一個無形的對象勋桶,比如數(shù)組和函數(shù)脱衙。
    這樣的對象沒有應(yīng)用程序接口,所以不能用一個類來表示例驹,更適合表示它們的是:唯一的和符號性的令牌捐韩,一個JavaScript對象,擁有一個友好的名字鹃锈,但不會與其它的同名令牌發(fā)生沖突荤胁。
    官方推薦使用InjectionToken實現(xiàn)(其實直接使用字符串也可以,最好還是按照官方推薦方式O(∩_∩)O)
import { InjectionToken } from '@angular/core';
export const TITLE = new InjectionToken <string>('title');
export const RUNNERS_UP= new InjectionToken <string>('RunnersUP');
providers:[
       {provide:TITLE, useValue: 'Hero of the Month'},
       {RUNNERS_UP, useFactory: runnersUpFactory(2),dep[Hero, HeroService]}
]
注冊提供商

可以在NgModule或者組件中注冊提供商
通常推薦在對應(yīng)的模塊(NgModule)中注冊提供商仪召,除非你必須把服務(wù)實例的范圍限制到某個組件及其子組件樹

  1. 在NgModule中注冊提供商
@NgModule({
    imports:[],
    declarations:[],
    providers:[ HeroService ]
})

2.在組件中注冊提供商

@Component({
    selector:'my-heros',
    template:`<h2></h2>`
    providers:[ HeroService ]
})
服務(wù)

在寫一個服務(wù)時必須注意@Injectable() 是必不可少的,除非你不打算注入這個服務(wù)松蒜,因為@Injectable()相當(dāng)于C++中的new()

import { Injectable } from '@angular/core';
@Injectable()
export class HeroService {
}

如何使用已注冊的服務(wù)?在組件或者服務(wù)的構(gòu)造函數(shù)中注入即可

constructor(
    public heroService: HeroService 
  ) {}

所有被注入的服務(wù)在angular中總是單例的扔茅,肯定有童鞋要問了,那我需要多實例的怎么辦秸苗?
angular應(yīng)用程序有多個依賴注入器召娜,組成了一個與組件樹平行的樹狀結(jié)構(gòu),所以可以在任何組件級別提供和建立服務(wù)惊楼,當(dāng)組件申請一個依賴時玖瘸,angular會從該組件本身的注入器開始,沿著依賴注入器的樹向上查找檀咙,所以要實現(xiàn)多實例雅倒,在組件內(nèi)注入服務(wù)即可

@host @Optional
有時候我們想限定依賴查找方式,比如只想讓組件向上搜索到宿主組件弧可,可以使用@host蔑匣,當(dāng)組件一層層向上查找沒有找到注冊的服務(wù)時,就會拋出錯誤棕诵,如果不想拋出錯誤裁良,可以使用@Optional,它會把注入?yún)?shù)設(shè)置為null

import { Host } from '@angular/core';
constructor( @Host heroService: HeroService ) {}
import { Optional } from '@angular/core';
constructor( @Optional heroService: HeroService ) {}

總結(jié)

angularjs中依賴注入涉及的知識面很多校套,本文只是作了一個簡單介紹价脾,更詳細內(nèi)容參考官方文檔和API

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市笛匙,隨后出現(xiàn)的幾起案子侨把,更是在濱河造成了極大的恐慌犀变,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,639評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件座硕,死亡現(xiàn)場離奇詭異弛作,居然都是意外死亡,警方通過查閱死者的電腦和手機华匾,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,277評論 3 385
  • 文/潘曉璐 我一進店門映琳,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人蜘拉,你說我怎么就攤上這事萨西。” “怎么了旭旭?”我有些...
    開封第一講書人閱讀 157,221評論 0 348
  • 文/不壞的土叔 我叫張陵谎脯,是天一觀的道長。 經(jīng)常有香客問我持寄,道長源梭,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,474評論 1 283
  • 正文 為了忘掉前任稍味,我火速辦了婚禮废麻,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘模庐。我一直安慰自己烛愧,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 65,570評論 6 386
  • 文/花漫 我一把揭開白布掂碱。 她就那樣靜靜地躺著怜姿,像睡著了一般。 火紅的嫁衣襯著肌膚如雪疼燥。 梳的紋絲不亂的頭發(fā)上沧卢,一...
    開封第一講書人閱讀 49,816評論 1 290
  • 那天,我揣著相機與錄音醉者,去河邊找鬼搏恤。 笑死,一個胖子當(dāng)著我的面吹牛湃交,可吹牛的內(nèi)容都是我干的熟空。 我是一名探鬼主播,決...
    沈念sama閱讀 38,957評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼搞莺,長吁一口氣:“原來是場噩夢啊……” “哼息罗!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起才沧,我...
    開封第一講書人閱讀 37,718評論 0 266
  • 序言:老撾萬榮一對情侶失蹤迈喉,失蹤者是張志新(化名)和其女友劉穎绍刮,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體挨摸,經(jīng)...
    沈念sama閱讀 44,176評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡孩革,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,511評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了得运。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片膝蜈。...
    茶點故事閱讀 38,646評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖熔掺,靈堂內(nèi)的尸體忽然破棺而出饱搏,到底是詐尸還是另有隱情,我是刑警寧澤置逻,帶...
    沈念sama閱讀 34,322評論 4 330
  • 正文 年R本政府宣布推沸,位于F島的核電站,受9級特大地震影響券坞,放射性物質(zhì)發(fā)生泄漏鬓催。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,934評論 3 313
  • 文/蒙蒙 一恨锚、第九天 我趴在偏房一處隱蔽的房頂上張望宇驾。 院中可真熱鬧,春花似錦眠冈、人聲如沸飞苇。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,755評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至雨让,卻和暖如春雇盖,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背栖忠。 一陣腳步聲響...
    開封第一講書人閱讀 31,987評論 1 266
  • 我被黑心中介騙來泰國打工崔挖, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人庵寞。 一個月前我還...
    沈念sama閱讀 46,358評論 2 360
  • 正文 我出身青樓狸相,卻偏偏與公主長得像,于是被迫代替她去往敵國和親捐川。 傳聞我的和親對象是個殘疾皇子脓鹃,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,514評論 2 348

推薦閱讀更多精彩內(nèi)容

  • 版本:Angular 5.0.0-alpha 依賴注入是重要的應(yīng)用設(shè)計模式。它使用得非常廣泛古沥,以至于幾乎每個人都稱...
    soojade閱讀 2,986評論 0 3
  • 什么是依賴性注入瘸右? 依賴性注入( Dependency Injection )其實不是 Angular 獨有的概念...
    接灰的電子產(chǎn)品閱讀 4,041評論 3 18
  • 一娇跟、什么是依賴注入 控制反轉(zhuǎn)(IoC) 控制反轉(zhuǎn)的概念最早在2004年由Martin Fowler提出,是針對面向...
    Keriy閱讀 3,172評論 0 8
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理太颤,服務(wù)發(fā)現(xiàn)苞俘,斷路器,智...
    卡卡羅2017閱讀 134,633評論 18 139
  • 時間管理龄章,一生都要陪伴的練習(xí)吃谣,這是第二次看此書,也是第一次寫心得瓦堵,自己的心情很高興基协,因為自己開始有點清醒了。 葉武...
    海豚的世界閱讀 1,976評論 3 6