依赖注入
依赖注入(DI)是一个经典的设计模式, 主要是用来处理组件如何获得依赖的问题。关于DI,推荐阅读Martin Flower的文章(http://martinfowler.com/articles/injection.html )。
Angular注入器会负责创建angular组件,解决组件之间的依赖以及依赖注入等职责。
使用依赖注入
依赖注入在angular应用代码中使用很频繁。我们可以在定义组件或者在模块的run和config块中使用。
- 可在angular组件(控制器、服务、过滤器、指令、动画等)的构造方法或工厂方法中声明依赖关系。可以向这些组件中注入服务(service)或者值(value)类型的依赖。
- 可为控制器添加一些特殊的依赖,我们将在下面具体介绍。
- 可在模块的run方法中定义依赖,可被注入的依赖包括服务(service)、值(value)和参量(constant)。注意.在run方法中不能注入"provider"类型的依赖.
- 可在模块的config中声明“provider”和“constant”类型的依赖,但不能注入service和value组件。
工厂方法
angular中的指令、服务或者过滤器可以通过工厂方法定义。工厂方法是模块(module)的子方法。通常推荐按下面的方式使用工厂方法:
angular.module('myModule', []) .factory('serviceId', ['depService', function(depService) { // ... }]) .directive('directiveName', ['depService', function(depService) { // ... }]) .filter('filterName', ['depService', function(depService) { // ... }]);
模块方法
angular模块提供了config和run方法方便开发者为模块添加配置和运行上下文的设置。和工厂方法类似,我们可以在config和run方法中定义依赖。例如:
angular.module('myModule', []) .config(['depProvider', function(depProvider) { // ... }]) .run(['depService', function(depService) { // ... }]);
控制器
控制器的构造方法主要用来定义模板中所用的模型数据和行为。通常推荐按如下用法使用构造器:
someModule.controller('MyController', ['$scope', 'dep1', 'dep2', function($scope, dep1, dep2) { ... $scope.aMethod = function() { ... } ... }]);
angular应用中可存在多个控制器实例,而服务组件是单例.
除了service, value类的依赖, 控制器中还注入一下依赖:
- $scope: 控制器是与某个DOM元素通过作用域相关联。其他类型的组件只能访问$rootScope服务。
- resolves : 如果在路由中实例化控制器,那么在路由里面解析的任何值域都可以作为依赖注入到控制器。
依赖注解
angular在执行某些方法(例如在服务的工厂方法、控制器构造方法)时会借助注入器(injector)。 因此我们需要在这些方法中加入标注来通知注入器哪些依赖需要被注入。可以通过以下三种方式注入服务:
- 通过数组标注在方法的参数中声明依赖(优先考虑)
- 定义在控制器构造方法的$inject属性中
- 通过方法参数名隐式的添加(有些注意事项)
数组标注
优先考虑用该方式为组件定义依赖,例如:
someModule.controller('MyController', ['$scope', 'greeter', function($scope, greeter) { // ... }]);
在代码中通过在第二个数组类型的参数中声明了'$scope','greeter'等依赖,数组最后一个元素为实际的构造方法,注意在构造方法的参数列表与其面的数组元素是一一对应的。
$inject属性
我们还可以通过为控制器的构造方法添加$inject属性,并在该属性中添加依赖的方式定义依赖。
var MyController = function($scope, greeter) { // ... } MyController.$inject = ['$scope', 'greeter']; someModule.controller('MyController', MyController);
注意$inject中依赖的顺序与构造方法中的参数需保持一致。
隐式声明依赖
最简单的声明依赖的方式就是让设构造方法的参数与依赖的名字一样。
someModule.controller('MyController', function($scope, greeter) { // ... });
注入器可以从函数的参数名中推断所依赖的服务。上面的函数中声明了$scope和greeter服务作为依赖。 这种方式可是代码更加简洁,但这种方式不能和Javascript的代码混淆器一起使用。可以通过ng-annotate在minifying之前隐式的添加依赖。
Strict Mode
通过在ng-app所在的DOM元素中添加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模式下使用隐式的标注会报错, 例如:
angular.module('myApp', []) .factory('willBreak', function($rootScope) { // $rootScope is implicitly injected }) .run(['willBreak', function(willBreak) { // Angular will throw when this runs }]);
当willBreak服务被实例化时,factory方法中由于参数$rootScope在前面的数组元素中声明而导致与依赖不匹配会报错。特别是使用ng-annotate时,该模式会保证所有应用组件的依赖被显示地声明。
如果用angular.bootstrap手动启动angular应用,我们可以通过设置config中的strictDi属性,启动strict模式。
angular.bootstrap(document, ['myApp'], { strictDi: true });
依赖注入的优点
在介绍依赖注入的优点之前我们简要介绍一下依赖注入模式。
我们可以通过三种方式让组件获得所需的依赖:
1. 在组件中创建依赖,例如通过new
2. 在全局上下文环境中查找依赖,通常为全局变量
3. 在组件需要依赖的时候自动注入依赖,例如Spring、Angular
前面两种方式都无法避免硬编码, 这样会增加代码的耦合度,变更会非常麻烦,也不利于测试。
第三种方式是最可行的,这种方式将查找注入依赖的职责统一转给了另一方方(容器)。
function SomeClass(greeter) { this.greeter = greeter; } SomeClass.prototype.doSomething = function(name) { this.greeter.greet(name); }
在上面的代码中, SomeClass并没有关注创建和查找greeter依赖,而只是简单的作为构造器的参数传入。这样负责创建SomeClass实例的代码会负责创建并注入依赖。
angular注入器($injector类似于spring容器)负责创建、查找注入依赖, 每个module都会有自己的注入器。
如下代码,可在module方法的第二参数中声明依赖的模块,通过工厂方法构造greeter服务,该服务依赖于$window服务, greeter服务包含了greet方法调用$wondow服务。
// Provide the wiring information in a module var myModule = angular.module('myModule', []); myModule.factory('greeter', function($window) { return { greet: function(text) { $window.alert(text); } }; });
我们还可以通过如下代码创建一个注入器,里面包含了myModule和ng模块, 这样我们就可以获得这两个模块中组件。
var injector = angular.injector(['myModule', 'ng']); var greeter = injector.get('greeter');
似乎是解决了硬编码注入依赖的问题,但新的问题是injector如何贯穿整个应用。通过模板中声明式的标签,我们可以解决新的问题。
<div ng-controller="MyController"> <button ng-click="sayHello()">Hello</button> </div> function MyController($scope, greeter) { $scope.sayHello = function() { greeter.greet('Hello World'); }; }
Angular在编译模板阶段为ng-controller指令实例化MyController以及注入相关的依赖。
injector.instantiate(MyController);
以上介绍了Angular中依赖注入的原理,这种方式极大的简化了代码。我们将在下一章中详细介绍模板。
相关推荐
NULL 博文链接:https://boyitech.iteye.com/blog/2167272
7. **合作博弈与联盟博弈**:合作博弈允许玩家形成联盟,共同制定策略以增加整体利益。而联盟博弈则研究这些联盟如何形成和破裂。 8. **演化博弈论**:考虑了玩家策略随时间演化的动态过程,最著名的例子是演化稳定...
论文研究-不确定性下多目标博弈中弱Pareto-NS均衡的存在性.pdf, 在已知不确定参数变化范围的假设下, 研究了多目标博弈中弱Pareto-NS均衡点的存在性问题. 首先结合非合作...
1.版本:matlab2014/2019a/2024a 2.附赠案例数据可直接运行matlab程序。 3.代码特点:参数化编程、参数可方便更改、代码编程思路清晰、注释明细。 4.适用对象:计算机,电子信息工程、数学等专业的大学生课程...
### 博弈论专题知识点详解 #### 一、博弈论概览 博弈论,又称对策论,是现代数学的一个重要分支,主要研究在各种策略情况下,参与者如何做出决策以达到自身利益最大化。这一理论不仅在数学领域有广泛的应用,同时...
哈佛大学的博弈论讲义是这个领域的权威资料之一,深受学者和学生们的喜爱。本讲义深入浅出地介绍了博弈论的基本概念、理论与应用,帮助读者理解在竞争与合作中的决策制定。 首先,我们要理解博弈论的核心概念——...
2. **完全信息动态博弈** - 这部分涉及博弈的动态过程,我们将深入研究子博弈精炼纳什均衡,这是考虑到博弈的各个阶段,参与者如何在每个阶段做出最优决策。 3. **不完全信息静态博弈** - 在参与者掌握的信息不完全...
微观经济学讲义-第13章博弈论
势博弈与时变Log-linear分布式拓扑控制算法 势博弈与时变Log-linear分布式拓扑控制算法是为了解决UWSNs(Underwater Wireless Sensor Networks,水下无线传感器网络)中网络拓扑控制不稳定、频繁变化引起的网络能耗...
2019年2季度大类资产配置报告:从基本面博弈转向资金面博弈-华泰证券-20190424.pdf
本讲义详细介绍了非合作博弈理论和信息经济学的相关概念。 首先,讲义涵盖了非合作博弈理论的基础,包括完全信息静态博弈。在完全信息静态博弈中,所有参与者都了解游戏的所有规则、支付矩阵和对手的策略。纳什均衡...
计算博弈第二讲-V61 计算博弈是自动化研究所 University of Chinese of Academy of Sciences 的一门专业普及课,旨在让学生理解博弈的基本概念、方法和应用。第二讲的主要内容是博弈表示方法、常见博弈类型和博弈的...
七所大学的博弈论讲义,包括哈佛大学.卡内基梅隆大学.芝加哥大学.加利福尼亚大学(圣. 迭戈校区).加利福尼亚
博弈是什么意思-博弈之道须正矣.docx
讲义第三章详细讲解了子博弈精炼纳什均衡,这是一种动态博弈的解概念,要求均衡策略不仅要在初始阶段是最佳的,而且在任何可能的子博弈中也必须是最优的。以房地产开发项目的例子来说明,开发商A和B在面对不确定市场...
人机博弈。PDF中文版。。。。。。。。。。。。。。。。。。。。。。。。。
基于混沌博弈优化算法CGO-BiTCN-BiGRU-Attention的风电预测算法研究Matlab实现.rar
奶粉行业首次覆盖报告:存量博弈,国产崛起-20210407
本讲义主要涵盖了非合作博弈理论和信息经济学的核心概念。 首先,非合作博弈理论是博弈论的基础,它描述了两个或多个独立决策者之间的互动,这些决策者无法通过正式协议来协调行动。在完全信息静态博弈中,所有参与...