[关闭]
@frank-shaw 2016-09-22T03:33:27.000000Z 字数 3887 阅读 1953

angluar中的依赖注入

angular.js


参考文章:
http://www.alloyteam.com/2015/09/angularjs-study-of-dependency-injection/
http://www.cnblogs.com/xingyukun/archive/2007/10/20/931331.html
http://www.admin10000.com/document/6711.html

理解依赖注入

依赖

如果在 Class A 中,有 Class B 的实例,则称 Class A 对 Class B 有一个依赖。例如下面类 Human 中用到一个 Father 对象,我们就说类 Human 对类 Father 有一个依赖。

  1. public class Human {
  2. ...
  3. Father father;
  4. ...
  5. public Human() {
  6. father = new Father();
  7. }
  8. }

仔细看这段代码我们会发现存在一些问题:
(1). 如果现在要改变 father 生成方式,如需要用new Father(String name)初始化 father,需要修改 Human 代码;
(2). 如果想测试不同 Father 对象对 Human 的影响很困难,因为 father 的初始化被写死在了 Human 的构造函数中;
(3). 如果new Father()过程非常缓慢,单测时我们希望用已经初始化好的 father 对象 Mock 掉这个过程也很困难。

依赖注入

上面将依赖在构造函数中直接初始化是一种 Hard init 方式,弊端在于两个类不够独立,不方便测试。我们还有另外一种 Init 方式,如下:

  1. public class Human {
  2. ...
  3. Father father;
  4. ...
  5. public Human(Father father) {
  6. this.father = father;
  7. }
  8. }

上面代码中,我们将 father 对象作为构造函数的一个参数传入。在调用 Human 的构造方法之前外部就已经初始化好了 Father 对象。像这种非自己主动初始化依赖,而通过外部来传入依赖的方式,我们就称为依赖注入。
现在我们发现上面 1 中存在的两个问题都很好解决了,简单的说依赖注入主要有两个好处:
(1). 解耦,将依赖之间解耦。
(2). 因为已经解耦,所以方便做单元测试,尤其是 Mock 测试。

依赖注入有一个很大的特点:程序运行阶段才产生依赖关系,在编译阶段并不产生这个关系。降低程序间的耦合度。

实现依赖注入

为了理解angularJS中的依赖注入,我们先来尝试一下没有明确使用angularJS的前提下,我们如何来模仿依赖注入。

首先,我们要有一个注入器,里面必须包含注册函数与resolve函数。

  1. var inject = {
  2. dependencies : {},
  3. register : function(key, value){
  4. this.dependencies[key] = value;
  5. },
  6. resolve : function(deps, func, scope){
  7. var arr = [];
  8. for(var i = 0; i<deps.length; i++){
  9. if(this.dependencies.hasOwnProperty(deps[i])){
  10. arr.push(this.dependencies[deps[i]]);
  11. }
  12. }
  13. console.log(arr);
  14. return function(){
  15. func.apply(scope || {}, arr);
  16. }
  17. }
  18. };

思路很简单,注册的时候通过map容器来存放《名字, 真正功能》之间的关联,然后在resolve的时候通过function.apply()将函数的参数与真正功能关联起来。

  1. inject.register("$http", {"get": function(){console.log("get")}});
  2. inject.register("scope",{"test": " 111"});
  3. var MyController = function($http, $scope){
  4. $scope.test = 1;
  5. $http.get();
  6. }
  7. MyController = inject.resolve(["$http", "scope"], MyController);
  8. //此时MyController中的参数一$http 对应的就是 {"get": function(){console.log("get")}}
  9. //参数二$scope 对应的就是{"test": " 111"}
  10. MyController();

这大概就是其具体原理了。但是值得注意的是,上面的程序中如果参数调换顺序的话,那么是无法正常运行的。如果想要了解如何修改程序可以让其参数调换顺序不受影响,可以参考angularJS的源代码。那么在使用angularJS的情况下,

AngularJS依赖注入类型

依赖注入的类型包括:依赖module、 依赖service。

依赖module

依赖module的注入直接在module创建的时候就可以注入,只不过需要在HTML页面中加载所依赖module的源文件。举个例子:

  1. //index.js文件
  2. angular.module("dataRegistry", ["ngTable"]);
  3. //对应HTML文件
  4. <head>
  5. ...
  6. <script src="../ng-table.js"></script>
  7. </head>

假设依赖module特别多的话,这个时候需要使用bower来进行依赖module的管理。此处引进了bower。即使如此,bower能够自动下载所需要的module,但还是不能够自动加载到HTML页面中,这时,还是需要gulp来帮忙。这也就是gulp的概念了。我们的项目里面,gulp中通过设置gulpfile.js:

  1. var options = {
  2. src:"src",
  3. dist:"dist",
  4. tmp:"tmp",
  5. e2e:"e2e",
  6. wiredep:{
  7. directory: "bower_components",
  8. exclude: [/bootstrap-sass-official\/.*\.js/, /bootstrap\.css/]
  9. }
  10. };

其中,wiredep模块的作用就是自动化加载依赖module到HTML页面中。

依赖service

前面已经大致讲解了依赖注入的原理,那么我们现在可以来看看,angularJS中内置的service有哪些?各自功能是什么?

$timeout: 对应了 JS window.setTimeout 函数。可直接使用$timeout(function(){}, 1000);
$interval : 对应了 JS window.setInterval 函数。可直接使用$interval(function(){}, 1000);
$http : 服务向服务器发送请求,应用响应服务器传送过来的数据。用法演示: $http.get("welcome.htm").then(...); 更多关于$http的用法,可以参考网页:

$location: 返回当前页面的 URL 地址。用法演示:$location.absUrl();
$rootScope :rootscope是各个controller中scope的桥梁。用rootscope定义的值,可以在各个controller中使用(在所有controller里面都是可以直接用{{$root.xxx}}来显示)。
$scope: 数据绑定作用。html和单个controller之间的桥梁。

$modal: 该service只有一个方法open()用于创建对话框。
$modalInstance: 扩展了两个方法close(result)dismiss(reason),这些方法很容易关闭窗口并且不需要额外的控制器。

$animate: $animate服务提供了基本的DOM操作功能如在DOM里插入、移除和移动元素,以及添加和删除类。这个服务是ngAnimate的核心服务,为CSS和Javascript提供了高档次的动画。 更多的可以查看:http://www.lai18.com/content/5636288.html

$parse: 将angularJS表达式转换为函数。更多网址参考:https://docs.angularjs.org/api/ng/service/$parse http://www.cnblogs.com/ys-ys/p/4989682.html
$interpolate: http://www.cnblogs.com/ys-ys/p/4989682.html

$locale:provides localization rules for various Angular components
$state: 通常是在ng-route与ui-route上作为路由的跳转使用,常用方法就是路由跳转方法$state.go().

$q: angular中的Promise对象。可以参考网址http://www.111cn.net/wy/js-ajax/71384.htm

$cacheFactory: 创建缓存的工厂,通过构造缓存实例,就可以直接使用。https://docs.angularjs.org/api/ng/service/$cacheFactory

$window: 代替客户端使用的window类。由于window在JavaScript中是全局变量,容易引发误解。所以使用这个来替代。

当然,我们也可以自己创建依赖service,请查看这里:https://www.zybuluo.com/frank-shaw/note/509468

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注