AngularJs Dependency Injection(DI,依賴注入)
一、Dependency Injection(依賴注入)
依賴注入(DI)是一個(gè)軟件設(shè)計(jì)模式,處理代碼如何得到它所依賴的資源。
關(guān)于DI更深層次的討論,可以參觀Dependency Injection(http://en.wikipedia.org/wiki/Dependency_injection),Inversion of Control(http://martinfowler.com/articles/injection.html),也可以參觀軟件設(shè)計(jì)模式的書(shū)。
1. DI in a nutshell(簡(jiǎn)說(shuō)DI)
object或者function,只能夠通過(guò)以下三種方式獲取他們依賴的資源:
1) 可以通過(guò)new運(yùn)算符創(chuàng)建依賴的資源。
2) 可以通過(guò)全局變量查找依賴的資源。
3) 可以通過(guò)參數(shù)傳入依賴的資源。
1、2兩種方式,并不是最佳的,因?yàn)樗鼈儗?duì)依賴關(guān)系進(jìn)行hard code,這使得修改依賴關(guān)系時(shí),不是不可能,但會(huì)變得比較復(fù)雜。這對(duì)于測(cè)試來(lái)說(shuō)尤其是個(gè)問(wèn)題,通常在獨(dú)立測(cè)試時(shí),希望能夠提供模擬的依賴資源。
第3種方法相對(duì)來(lái)說(shuō)最可行,因?yàn)樗コ藦慕M件(component)中定位依賴的責(zé)任。依賴僅僅交給組件就可以了。
function SomeClass(greeter) { this.greeter = greeter } SomeClass.prototype.doSomething = function(name) { this.greeter.greet(name); }
上面的例子,SomeClass不用關(guān)心定位greeter這個(gè)依賴,它僅僅在運(yùn)行時(shí)傳遞greeter。
這樣是比較合適的,但它將獲取依賴資源的責(zé)任交給了負(fù)責(zé)構(gòu)建SomeClass的代碼那里。
為了管理創(chuàng)建依賴的責(zé)任,每一個(gè)angular應(yīng)用都有一個(gè)injector(http://code.angularjs.org/1.0.2/docs/api/angular.injector)。injector是一個(gè)服務(wù)定位器,負(fù)責(zé)定位并創(chuàng)建依賴的資源。
請(qǐng)求依賴,解決了hard code的問(wèn)題,但它意味著injector需要貫穿整個(gè)應(yīng)用。傳遞injector,會(huì)破壞Law of Demeter(http://baike.baidu.com/view/823220.htm)。為了糾正這個(gè)問(wèn)題,我們將依賴查找的責(zé)任轉(zhuǎn)給injector。
上面說(shuō)了那么多,看看下面經(jīng)我修改過(guò)的例子,合并了原文的兩個(gè)例子,分別在angular內(nèi)、外使用inject:
<!DOCTYPE HTML> <html lang="zh-cn" ng-app="MainApp"> <head> <meta charset="UTF-8"> <title>injector</title> </head> <body> <div ng-controller="MyController"> <button ng-click="sayHello()">Say Hello</button> </div> <script src="../angular-1.0.1.js" type="text/javascript"></script> <script type="text/javascript"> //創(chuàng)建OtherModule這個(gè)module,相當(dāng)于外部的module var otherModule = angular.module("OtherModule", []); //教injector如何創(chuàng)建"greeter" //注意,greeter本身需要依賴$window otherModule.factory("greeter", function ($window) { //這里是一個(gè)工廠方法,負(fù)責(zé)創(chuàng)建greet服務(wù) return { greet:function (text) { $window.alert(text); } }; }); //下面展示在非當(dāng)前module中,通過(guò)injector調(diào)用greet方法: //從module中創(chuàng)建新的injector //這個(gè)步驟通常由angular啟動(dòng)時(shí)自動(dòng)完成。 //必須引入'ng',angular的東東 //故意顛倒順序,暫時(shí)證實(shí)這玩意的順序是無(wú)所謂的。。 var injector = angular.injector(['OtherModule','ng']); //請(qǐng)求greeter這個(gè)依賴。 var g = injector.get("greeter"); //直接調(diào)用它~ g.greet("Hi~My Little Dada~"); //這里是當(dāng)前的主app,需要依賴OtherModule var mainApp = angular.module("MainApp", ["OtherModule"]); //留意Controller的定義函數(shù)的參數(shù),在這里直接注入$scope、greeter。 // greeter服務(wù)是在OtherModule中的 mainApp.controller("MyController",function MyController($scope,greeter) { $scope.sayHello = function() { greeter.greet("Hello Kitty~~"); }; } ); //ng-controller已經(jīng)在背后默默地做了這個(gè)事情 //injector.instantiate(MyController); </script> </body> </html>
注意,因?yàn)橛衝g-controller,初始化了MyController,它可以滿足MyController的所有依賴需要,讓MyController無(wú)須知道injector的存在。這是一個(gè)最好的結(jié)果。應(yīng)用代碼簡(jiǎn)單地請(qǐng)求它所需要的依賴而不需要處理injector。這樣設(shè)置,不會(huì)打破Law of Demeter。
二、Dependency Annotation(依賴注釋,說(shuō)明依賴的方式)
injector如何知道什么服務(wù)需要被注入呢?
應(yīng)用開(kāi)發(fā)者需要提供被injector用作解決依賴關(guān)系的注釋信息。所有angular已有的API函數(shù),都引用了injector,每一個(gè)文檔中提及的API都是這樣。下面是用服務(wù)名稱信息注釋我們的代碼的三個(gè)等同的方法。
1. Inferring Dependencies(隱含依賴)
這是獲取依賴資源的最簡(jiǎn)單的方式,但需要假定function的參數(shù)名稱與依賴資源的名稱一致。
function MyController($scope, greeter) { ... }
函數(shù)的injector,可以通過(guò)檢查函數(shù)定義并提取函數(shù)名稱,猜測(cè)需要注入的service的名稱(functionName.toString(),RegExp)。在上面的例子中,$scope和greeter是兩個(gè)需要被注入到函數(shù)的服務(wù)(名稱也一致)。
雖然這樣做很簡(jiǎn)單,但這方法在javascript混淆壓縮后就行不通了,因?yàn)閰?shù)名稱會(huì)被改變。這讓這個(gè)方式只能對(duì)pretotyping(產(chǎn)品可用性原型模擬測(cè)試法,http://www.pretotyping.org/,http://tech.qq.com/a/20120217/000320.htm)和demo應(yīng)用有作用。
2. $inject Annotation($inject注釋)
為了允許腳本壓縮器重命名函數(shù)的方法后,仍然能夠注入正確的服務(wù),函數(shù)必須通過(guò)$inject屬性來(lái)注釋依賴。$inject屬性是一個(gè)需要注入的服務(wù)的名稱的數(shù)組。
var MyController = function(renamed$scope, renamedGreeter) { ... } //這里依賴的東東,如果不在當(dāng)前的module中,它還是不認(rèn)識(shí)的。
//需要在當(dāng)前module中先依賴對(duì)應(yīng)的module。跟之前的例子差不多。但我不知道這是不是正確的方法。
MyController.$inject = ['$scope', 'greeter'];
需要小心的是,$inject的順序需要與函數(shù)聲明的參數(shù)順序保持一致。
這個(gè)注釋方法,對(duì)于controller聲明來(lái)說(shuō)是有用的,因?yàn)樗c函數(shù)一起指定注釋信息。
3. inline Annotation(行內(nèi)注釋)
有時(shí)候,不方便使用$inject注釋的方式,例如注釋directive的時(shí)候。
例如:
someModule.factory('greeter', function($window) { ...; });
因?yàn)樾枰R時(shí)變量(防止壓縮后不能使用),所以代碼會(huì)膨脹為:
var greeterFactory = function(renamed$window) { ...; }; greeterFactory.$inject = ['$window']; someModule.factory('greeter', greeterFactory);
由于這樣(代碼膨脹),angular還提供了第三種注釋風(fēng)格:
someModule.factory('greeter', ['$window', function(renamed$window) { ...; }]);
記住,所有注釋風(fēng)格都是等價(jià)的,可以被用在支持injection的angular中的任何地方。
三、Where can I user DI?
DI遍及整個(gè)angular。它通常使用在controller和factory方法中。
1. DI in controllers
controller是負(fù)責(zé)(描述)應(yīng)用行為的類。建議的controller聲明方法是:
var MyController = function(dep1, dep2) { ... } MyController.$inject = ['dep1', 'dep2']; MyController.prototype.aMethod = function() { ... }
2. Factory methods
factory方法是負(fù)責(zé)創(chuàng)建大多數(shù)angular對(duì)象。例如directive、service、filter。factory方法注冊(cè)在module中,建議的factory聲明方法是:
angualar.module('myModule', []). config(['depProvider', function(depProvider){ ... }]). factory('serviceId', ['depService', function(depService) { ... }]). directive('directiveName', ['depService', function(depService) { ... }]). filter('filterName', ['depService', function(depService) { ... }]). run(['depService', function(depService) { ... }]);
以上就是對(duì)AngularJS Dependency Injection 的資料整理后續(xù)繼續(xù)補(bǔ)充,謝謝大家對(duì)本站的支持!
- 自學(xué)實(shí)現(xiàn)angularjs依賴注入
- AngularJS $injector 依賴注入詳解
- AngularJS應(yīng)用開(kāi)發(fā)思維之依賴注入3
- AngularJS之依賴注入模擬實(shí)現(xiàn)
- AngularJS入門教程之XHR和依賴注入詳解
- AngularJS 依賴注入詳解及示例代碼
- AngularJS 依賴注入詳解和簡(jiǎn)單實(shí)例
- AngularJS學(xué)習(xí)筆記之依賴注入詳解
- 詳解Angularjs中的依賴注入
- AngularJs動(dòng)態(tài)加載模塊和依賴注入詳解
- 詳解AngularJS中的依賴注入機(jī)制
- AngularJS Module方法詳解
- AngularJS的依賴注入實(shí)例分析(使用module和injector)
相關(guān)文章
angular6的table組件開(kāi)發(fā)的實(shí)現(xiàn)示例
這篇文章主要介紹了angular6的table組件開(kāi)發(fā)的實(shí)現(xiàn)示例,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-12-12angular+bootstrap的雙向數(shù)據(jù)綁定實(shí)例
本篇文章主要介紹angular+bootstrap的雙向數(shù)據(jù)綁定的實(shí)例,具有很好的參考價(jià)值。下面跟著小編一起來(lái)看下吧2017-03-03利用JavaScript的AngularJS庫(kù)制作電子名片的方法
這篇文章主要介紹了利用JavaScript的AngularJS庫(kù)制作電子名片的方法,其中需要使用到HTML5的canvas畫(huà)布,需要的朋友可以參考下2015-06-06Angular.js與node.js項(xiàng)目里用cookie校驗(yàn)賬戶登錄詳解
這篇文章主要介紹了Angular.js與node.js項(xiàng)目里用cookie校驗(yàn)賬戶登錄的相關(guān)資料,文中介紹的非常詳細(xì),需要的朋友可以參考借鑒,下面來(lái)一起看看吧。2017-02-02利用angular自動(dòng)編譯andriod APK的繞坑經(jīng)歷分享
這篇文章主要給大家介紹了關(guān)于如何利用angular自動(dòng)編譯andriod APK的繞坑經(jīng)歷,文中通過(guò)示例代碼以及圖文介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者使用angular具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-03-03Angular實(shí)現(xiàn)form自動(dòng)布局
這篇文章主要介紹了Angular實(shí)現(xiàn)form自動(dòng)布局的相關(guān)資料,以代碼片段的形式分析了Angular實(shí)現(xiàn)form自動(dòng)布局的實(shí)現(xiàn)方法,感興趣的小伙伴們可以參考一下2016-01-01Angular5.0 子組件通過(guò)service傳遞值給父組件的方法
這篇文章主要介紹了Angular5.0 子組件通過(guò)service傳遞值給父組件的方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-07-07