AngularJs學習筆記--Dependency Injection(DI,依賴注入)

原版地址:http://code.angularjs.org/1.0.2/docs/guide/dijavascript

 

1、Dependency Injection(依賴注入)html

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

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

  1. DI in a nutshell(簡說DI)shell

  object或者function,只可以經過如下三種方式獲取他們依賴的資源:express

    1) 能夠經過new運算符建立依賴的資源。bootstrap

    2) 能夠經過全局變量查找依賴的資源。設計模式

    3) 能夠經過參數傳入依賴的資源。api

  一、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) {
        //這裏是一個工廠方法,負責建立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。

 

2、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中的任何地方。
 

3、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) {
      ...
}]);
 
 
 
 
 
 
 
 
 
 
 
 
  1. AngularJs學習筆記--bootstrap
  2. AngularJs學習筆記--html compiler
  3. AngularJs學習筆記--concepts
  4. AngularJs學習筆記--directive
  5. AngularJs學習筆記--expression
  6. AngularJs學習筆記--Forms
  7. AngularJs學習筆記--I18n/L10n
  8. AngularJs學習筆記--IE Compatibility
  9. AngularJs學習筆記--Modules
  10. AngularJs學習筆記--Scope
  11. AngularJs學習筆記--Dependency Injection
  12. AngularJs學習筆記--Understanding the Model Component
  13. AngularJs學習筆記--Understanding the Controller Component
  14. AngularJs學習筆記--E2E Testing
  15. AngularJs學習筆記--Understanding Angular Templates
  16. AngularJs學習筆記--Using $location
  17. AngularJs學習筆記--Creating Services
  18. AngularJs學習筆記--Injecting Services Into Controllers
  19. AngularJs學習筆記--Managing Service Dependencies
  20. AngularJs學習筆記--unit-testing
相關文章
相關標籤/搜索