1. 程式人生 > >angular學習(六)—— 依賴注入

angular學習(六)—— 依賴注入

依賴注入

依賴注入(DI)是一種處理元件如何獲得依賴的軟體設計模式,在Angular中,injector子系統負責建立元件,解決元件的依賴,並將它們提供給其他元件。

使用依賴注入

在Angular中DI是無處不在的,你可以用它來定義一個元件,也可以提供module實現run和config程式碼塊。
- 像services, directives, filters 和 animations這樣的元件都由一個工廠方法或者建構函式定義,在此service和value元件可以作為依賴注入到這些元件當中。
- Controllers通過一個建構函式定義,一樣service和value元件可以作為依賴注入到元件當中,但他們也有著特殊的依賴關係,我們在

angular學習(三)—— Controller 中有講到。
- Module的run方法接受一個函式,在函式的引數中作為依賴可以注入service,value和constant元件,但是不能注入providers。
- Module的config方法接受一個函式,在函式的引數中作為依賴可以注入provider和constant元件,但是不能注入service和value。

factory方法

directive, service, or filter都由一個工廠方法定義,該方法通過modules註冊。定義這個工廠方法推薦的寫法如下:

angular.module('myModule'
, []) .factory('serviceId', ['depService', function(depService) { // ... }]) .directive('directiveName', ['depService', function(depService) { // ... }]) .filter('filterName', ['depService', function(depService) { // ... }]);

module方法

我們可以指定module在配置和執行時需要呼叫的config方法和run方法。這些函式就像上面的工廠方法一樣可以注入依賴。

angular.module('myModule'
, []) .config(['depProvider', function(depProvider) { // ... }]) .run(['depService', function(depService) { // ... }]);

controller

controller能夠提供讓application可以在模板定義宣告性標記的行為(方法)。定義controller中使用依賴注入的推薦方法是用一個數組。

someModule.controller('MyController', ['$scope', 'dep1', 'dep2', function($scope, dep1, dep2) {
  ...
  $scope.aMethod = function() {
    ...
  }
  ...
}]);

和service不同的是,在同一個應用程式中可以有許多相同型別的控制器例項。
此外,控制器可以使用一些額外的依賴關係:

  • $scope:控制器與DOM中的一個元素相關聯,因此提供了以元素相對應的訪問範圍。其他元件(如service)只能訪問$rootScope服務
  • resolves: 如果controller被例項化為route的一部分,作為route的一部分解析的任何值都可用於注入控制器.

依賴註解

Angular呼叫通過注入呼叫一些函式時(比如service的工廠方法和controller),為了讓injector知道需要將哪些service注入到函式中,你需要對這些函式進行註解。這裡有三種註解方式:
- 內聯陣列註解,最好優先使用這種方式
- 用 $inject屬性註解
- 以函式的引數名字隱式註解,這種方式有一些警告。

內聯陣列註解

這是angular程式註解元件的首選方法,本系列的文章都是這種方式。

omeModule.controller('MyController', ['$scope', 'greeter', function($scope, greeter) {
  // ...
}]);

行內函數由所需依賴名字構成的字串列表和函式本身構成。當使用這種註解方式時要注意,內聯陣列中所需依賴名字字串順序和函式中的引數順序要一致。

$inject屬性註解

使用$inject屬性一樣可以做到這一點,$inject屬性是一個由所需依賴名字構成字串陣列。

var MyController = function($scope, greeter) {
  // ...
}
MyController.$inject = ['$scope', 'greeter'];
someModule.controller('MyController', MyController);

和內聯陣列註解一樣,函式中的依賴引數順序要和$inject 屬性數組裡的順序一致。

隱式註解

注意:如果你想最小化你的javascript程式碼時,如果使用了這種註解方式,service將會被重新命名,程式就會報錯。

獲得依賴最簡單的方法就是假定函式引數的名字就是所需依賴的名字。

someModule.controller('MyController', function($scope, greeter) {
  // ...
});

給出一個函式,injector可以通過檢查函式宣告和提取引數名稱來確定需要注入的service的名字。
這種註解方法的一個優點是,你不需要去關心陣列中的元素和函式的引數是否一致,你可以自由排列引數的順序。
但是你一旦對javascript做了最小化或者混淆操作,那麼函式將無法執行,因為引數會被重新命名。基於這些問題,我們建議避免這種風格的註解。

有一個好工具ng-annotate可以幫你在最小化前自動把你程式裡的所有的隱私註解更改為內聯陣列註解。
還有如果你決定採取這種方法,您可能希望使用ng-strict-di。

使用ng-strict-di指令

你可以在和ng-app同一個元素中新增一個ng-strict-di指令。

<!doctype html>
<html ng-app="myApp" ng-strict-di>
<body>
  I can add: {{ 1 + 2 }}.
  <script src="angular.js"></script>
</body>
</html>

在strict模式下,當一個服務試圖使用隱式註解時就會丟擲一個錯誤。
如下,包含了隱式註解的willBreak service。

angular.module('myApp', [])
.factory('willBreak', function($rootScope) {
  // $rootScope is implicitly injected
})
.run(['willBreak', function(willBreak) {
  // Angular will throw when this runs
}]);

當willBreak初始化時就會報錯,因為已經指定了strict模式。這可以用來保證ng-annotate工具已經把你程式的所有隱式註解修改為了內聯陣列註解。

如果你手動修改bootstrapping,你可以指定strictDi: true來達到同樣的效果。

angular.bootstrap(document, ['myApp'], {
  strictDi: true
});

為什麼使用依賴注入

一個元件(物件或者函式)獲得它需要的依賴的方法只有三種

  1. 元件去建立這個依賴,通常使用new操作符
  2. 元件去查詢一個依賴,引用一個全域性變數
  3. 元件可以得到一個依賴傳遞在它需要使用的地方

前兩個方法都不是最佳的,因為需要將依賴硬編碼到元件中。需要依賴需要修改的時候這就非常的困難。特別是在測試階段,為了測試的隔離性,常常需要提供一個模擬的依賴。
第三種方式是可行的,因為它把依賴的定位查詢的責任從元件中剝離出來,依賴僅僅是簡單地傳遞給元件。

function SomeClass(greeter) {
  this.greeter = greeter;
}

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

在上面的例子中SomeClass不需要關心greeter依賴的建立和查詢,僅僅需要在例項化時獲得greeter依賴即可。它把獲得依賴的責任丟給了程式碼結構設計。

為了管理依賴建立的責任,每個angular應用都有一個injector,injector是一個負責建立和查詢依賴的服務定位器。

下面是一個使用injector服務的例子:

/**Provide the wiring information in a module*/
var myModule = angular.module('myModule', []);

我們來看看injector如何建立greeter服務。注意greeter還依賴於$window服務,greeter服務是一個包含了greet函式的物件。

myModule.factory('greeter', function($window) {
  return {
    greet: function(text) {
      $window.alert(text);
    }
  };
});

在myModule中建立一個可以提供元件的injector,並且從injector中獲得greeter服務。(這通常由angular的bootstrap完成)

var injector = angular.injector(['ng', 'myModule']);
var greeter = injector.get('greeter');

這樣雖然也解決了依賴的硬編碼問題,但是意味著injector需要穿過整個應用,這樣就打破了迪米特法則。為了彌補這一點,我們在HTML模板使用宣告性符號把建立依賴的責任移交給injector,如下:

<div ng-controller="MyController">
  <button ng-click="sayHello()">Hello</button>
</div>
function MyController($scope, greeter) {
  $scope.sayHello = function() {
    greeter.greet('Hello World');
  };
}

當angular編譯這個html時,它處理到ng-controller,它將要求injector去建立controller例項和它的依賴。

injector.instantiate(MyController);

這些操作都是在後臺做的。通過ng-controller要求injector去例項化的方式,可以讓controller不知道injector的情況下,建立了MyController所有的依賴。應用程式無需理會injector,僅僅是簡單的宣告它所需要的依賴,這樣就不會打破迪米特法則。

整個過程圖示如下:
這裡寫圖片描述





如果我的文章對您有幫助,請用支付寶打賞:

相關推薦

angular學習—— 依賴注入

依賴注入 依賴注入(DI)是一種處理元件如何獲得依賴的軟體設計模式,在Angular中,injector子系統負責建立元件,解決元件的依賴,並將它們提供給其他元件。 使用依賴注入 在Angular中DI是無處不在的,你可以用它來定義一個元件,也可以提供

Spring.NET教程依賴注入(應用篇)

談到高階語言程式設計,我們就會聯想到設計模式;談到設計模式,我們就會說道怎麼樣解耦合。而Spring.net的IoC容器其中的一種用途就是解耦合,其最經典的應用就是:依賴注入(Dependeny Injection)簡稱DI,目前DI是最優秀的解耦方式之一。下面我就來談談依賴注入的應用場景。 我模擬了三種不

Spring Boot IoC學習依賴注入DI

四、依賴注入DI 簡介 Bean之間的依賴稱為依賴注入。 例:人穿不同的鞋子去完成不同的活動。比如,人穿籃球鞋去打籃球,穿跑步鞋去跑步鍛鍊,穿皮鞋去上班等等。所以人和鞋子就是依賴關係。 我們用程式碼來展現依賴,定義兩個介面,一個事人類(Person),一個是鞋子

spring框架學習依賴注入

    spring框架為我們提供了三種注入方式,分別是set注入,構造方法注入,介面注入。介面注入不作要求,下面介紹前兩種方式。 1,set注入   採用屬性的set方法進行初始化,就成為set注

Spring入門學習泛型依賴注入 第十三節

Spring入門學習(泛型依賴注入) Spring4泛型依賴注入 Spring4泛型依賴注入 建立泛型類BaseRepository<T>,BaseService<T>,BaseService中注入了BaseRe

Guice 學習使用Provider注入服務 Provider Inject Service

1、定義介面 package com.guice.providerInject; import com.google.inject.ProvidedBy; public interface Service { public void execu

java學習面向對象 final關鍵字

hello int java學習 xtend 最終 .sh 方法 div ext 1.被fnial修飾的方法不能被重寫,常見的為修飾類,方法,變量 /* final可以修飾類,方法,變量 特點: final可以修飾類,該類不能被繼

線程學習--單例和多線程、ThreadLocal

pen single cal final ride args ash public 線程 一、ThreadLocal 使用wait/notify方式實現的線程安全,性能將受到很大影響。解決方案是用空間換時間,不用鎖也能實現線程安全。 來看一個小例子,在線程內的set、get

Linux 網卡驅動學習應用層、tcp 層、ip 層、設備層和驅動層作用解析

local acc 每次 letter auto sizeof style article inode 本文將介紹網絡連接建立的過程、收發包流程,以及當中應用層、tcp層、ip層、設備層和驅動層各層發揮的作用。 1、應用層 對於使用socket進行網絡連接的serv

RabbitMQ學習:遠程結果調用

cells actor ble 隨機 get getenv all 求和 int 場景:我們需要在傳輸消息時得到結果 客服端在發送請求時會發送回調隊列,服務端處理事情完成後會將結果返回到回調隊列中,在增加關聯標誌關聯每個請求和服務返回 客戶端代碼: public

Django學習---博客文章頁面的超鏈接設置

_id 三個參數 name app dex pla django (六) pat Django中的超鏈接 超鏈接的目標地址 href後面是目標地址 template中可以用 {% url ‘app_name : url_name’ param %} app_name:

別樣JAVA學習繼承下(2.3)異常下

關閉 exit dsm 練習 方便 pub xtend 運行 script 1、RuntimeException Exception中有一個特殊的子類異常RuntimeException執行時異常。 假設在函數內容拋出該異常,函數上能夠不用聲明。編譯一樣

python學習---文件操作

not game seek read 終端設備 fas uic med ear 文件操作文件操作流程 1、打開文件,得到文件句柄並賦值給一個變量 2、通過句柄對文件進行操作 3、關閉文件現有文件如下: Somehow, it seems the love I knew

linux學習絕對路徑、相對路徑、cd、mkdir、rmdir、rm

director shell script local mkdir -p create deb blog 目錄 一、絕對路徑 就是從根開始的,如:/root、/usr/local。 二、相對路徑 相對於當前路徑的,比如我們在當前路徑下建立了一個a.txt。 [root@i

Angular學習

字符串 inf bubuko 綁定屬性 lar 引入 手動配置 back 生成 1.創建模塊,命令行輸入: ng g component components/news 自動生成: 1.2跟模塊的app.module.ts 裏會自動引入 news 模塊,但是@NgMod

Angular學習

分享 cto post請求 ext com ade [] png align Angular服務 1.創建服務: ng g service services/storage 2.註入服務 在根目錄的app.module.ts裏引入服務。並且在providers:[]裏寫入

webpack學習打包壓縮js和css

網頁 com 換行符 最小化 合並 標準 註意 resolve hash 打包壓縮js與css 由於webpack本身集成了UglifyJS插件(webpack.optimize.UglifyJsPlugin)來完成對JS與CSS的壓縮混淆,無需引用額外的插件, 其命令we

Docker學習: 網絡使用與配置

sock AR -i 回顧 覆蓋 htm 參考 ble dock 特別聲明:   博文主要是學習過程中的知識整理,以便之後的查閱回顧。部分內容來源於網絡(如有摘錄未標註請指出)。內容如有差錯,也歡迎指正! =============系列文章============= 1

modSecurity規則學習——檢測模式

debug move 都是 action pattern denied 復雜 不用 rup 傳統檢測模式-自主規則 傳統檢測模式所有規則都是“閉環”的模式。就像HTTP本身一樣,單獨的規則是無狀態的。這意味著規則之間不共享信息,每個規則都沒有關於任何先前規則匹配的信息。它僅

FFMpeg學習 用libavfilter對視頻尺寸進行裁切

example doc 分享 col 參數 tails 環境 坐標 通過 在ffmpeg框架中,濾鏡(filter)功能通過libavfilter庫實現。 一個filter可以同時有多個輸入和輸出。以圖為例: 圖中的一系列操作共使用了四個filter,分