AngularJs Dependency Injection(DI,依賴注入)_AngularJS

來源:互聯網
上載者:User

一、Dependency Injection(依賴注入)

  依賴注入(DI)是一個軟體設計模式,處理代碼如何得到它所依賴的資源。

  關於DI更深層次的討論,可以參觀Dependency Injection(http://en.wikipedia.org/wiki/Dependency_injection),Inversion of Control(http://martinfowler.com/articles/injection.html),也可以參觀軟體設計模式的書。

  1. DI in a nutshell(簡說DI)

  object或者function,只能夠通過以下三種方式擷取他們依賴的資源:

    1) 可以通過new運算子建立依賴的資源。

    2) 可以通過全域變數尋找依賴的資源。

    3) 可以通過參數傳入依賴的資源。

  1、2兩種方式,並不是最佳的,因為它們對依賴關係進行hard code,這使得修改依賴關係時,不是不可能,但會變得比較複雜。這對於測試來說尤其是個問題,通常在獨立測試時,希望能夠提供類比的依賴資源。

  第3種方法相對來說最可行,因為它去除了從組件(component)中定位依賴的責任。依賴僅僅交給組件就可以了。

function SomeClass(greeter) {   this.greeter = greeter}SomeClass.prototype.doSomething = function(name) {   this.greeter.greet(name);}

  上面的例子,SomeClass不用關心定位greeter這個依賴,它僅僅在運行時傳遞greeter。

  這樣是比較合適的,但它將擷取依賴資源的責任交給了負責構建SomeClass的代碼那裡。

  為了管理建立依賴的責任,每一個angular應用都有一個injector(http://code.angularjs.org/1.0.2/docs/api/angular.injector)。injector是一個服務定位器,負責定位並建立依賴的資源。

  請求依賴,解決了hard code的問題,但它意味著injector需要貫穿整個應用。傳遞injector,會破壞Law of Demeter(http://baike.baidu.com/view/823220.htm)。為了糾正這個問題,我們將依賴尋找的責任轉給injector。

  上面說了那麼多,看看下面經我修改過的例子,合并了原文的兩個例子,分別在angular內、外使用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">  //建立OtherModule這個module,相當於外部的module  var otherModule = angular.module("OtherModule", []);  //教injector如何建立"greeter"  //注意,greeter本身需要依賴$window  otherModule.factory("greeter", function ($window) {    //這裡是一個Factory 方法,負責建立greet服務    return {      greet:function (text) {        $window.alert(text);      }    };  });  //下面展示在非當前module中,通過injector調用greet方法:  //從module中建立新的injector  //這個步驟通常由angular啟動時自動完成。  //必須引入'ng',angular的東東  //故意顛倒順序,暫時證實這玩意的順序是無所謂的。。  var injector = angular.injector(['OtherModule','ng']);  //請求greeter這個依賴。  var g = injector.get("greeter");  //直接調用它~  g.greet("Hi~My Little Dada~");  //這裡是當前的主app,需要依賴OtherModule  var mainApp = angular.module("MainApp", ["OtherModule"]);  //留意Controller的定義函數的參數,在這裡直接注入$scope、greeter。  // greeter服務是在OtherModule中的  mainApp.controller("MyController",function MyController($scope,greeter) {      $scope.sayHello = function() {        greeter.greet("Hello Kitty~~");      };    }  );  //ng-controller已經在背後默默地做了這個事情  //injector.instantiate(MyController);</script></body></html>

 注意,因為有ng-controller,初始化了MyController,它可以滿足MyController的所有依賴需要,讓MyController無須知道injector的存在。這是一個最好的結果。應用代碼簡單地請求它所需要的依賴而不需要處理injector。這樣設定,不會打破Law of Demeter。

二、Dependency Annotation(依賴注釋,說明依賴的方式)

  injector如何知道什麼服務需要被注入呢?

  應用開發人員需要提供被injector用作解決依賴關係的注釋資訊。所有angular已有的API函數,都引用了injector,每一個文檔中提及的API都是這樣。下面是用服務名稱資訊注釋我們的代碼的三個等同的方法。

  1. Inferring Dependencies(隱含依賴)

  這是擷取依賴資源的最簡單的方式,但需要假定function的參數名稱與依賴資源的名稱一致。

function MyController($scope, greeter) {   ...}

  函數的injector,可以通過檢查函數定義並提取函數名稱,猜測需要注入的service的名稱(functionName.toString(),RegExp)。在上面的例子中,$scope和greeter是兩個需要被注入到函數的服務(名稱也一致)。

  雖然這樣做很簡單,但這方法在javascript混淆壓縮後就行不通了,因為參數名稱會被改變。這讓這個方式只能對pretotyping(產品可用性原型類比測試法,http://www.pretotyping.org/,http://tech.qq.com/a/20120217/000320.htm)和demo應用有作用。

  2. $inject Annotation($inject注釋)

  為了允許指令碼壓縮器重新命名函數的方法後,仍然能夠注入正確的服務,函數必須通過$inject屬性來注釋依賴。$inject屬性是一個需要注入的服務的名稱的數組。

var MyController = function(renamed$scope, renamedGreeter) {   ...}//這裡依賴的東東,如果不在當前的module中,它還是不認識的。
//需要在當前module中先依賴對應的module。跟之前的例子差不多。但我不知道這是不是正確的方法。
MyController.$inject = ['$scope', 'greeter'];

  需要小心的是,$inject的順序需要與函式宣告的參數順序保持一致。

  這個注釋方法,對於controller聲明來說是有用的,因為它與函數一起指定注釋資訊。

  3. inline Annotation(行內注釋)

  有時候,不方便使用$inject注釋的方式,例如注釋directive的時候。

  例如:

someModule.factory('greeter', function($window) {  ...;});

  因為需要臨時變數(防止壓縮後不能使用),所以代碼會膨脹為:

var greeterFactory = function(renamed$window) {  ...;};greeterFactory.$inject = ['$window'];someModule.factory('greeter', greeterFactory);

  由於這樣(代碼膨脹),angular還提供了第三種注釋風格:

someModule.factory('greeter', ['$window', function(renamed$window) {   ...;}]);

  記住,所有注釋風格都是等價的,可以被用在支援injection的angular中的任何地方。

三、Where can I user DI?

  DI遍及整個angular。它通常使用在controller和factory方法中。

  1. DI in controllers

  controller是負責(描述)應用行為的類。建議的controller聲明方法是:

var MyController = function(dep1, dep2) {   ...}MyController.$inject = ['dep1', 'dep2'];MyController.prototype.aMethod = function() {   ...}

  2. Factory methods

  factory方法是負責建立大多數angular對象。例如directive、service、filter。factory方法註冊在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) {    ...}]);

      以上就是對AngularJS Dependency Injection 的資料整理後續繼續補充,謝謝大家對本站的支援!

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.