依赖注入简述 | DI in a nutshell


对象或者函数只有以下3种获取其依赖(的对象)引用的方式:


  1. 依赖可以被使用者自己创建,通过 new 操作符.
  2. 依赖可以通过全局变量(如 window)来查找并引用
  3. 依赖可以在需要的地方被传入

前两种创建或查找依赖的方式并不是最优的,因为他们对依赖进行了硬编码. 这就使得当依赖变得不可用时,要修改依赖相关的代码变得非常困难和繁琐。在测试中更是有问题,因为通常需要通过模拟依赖来进行隔离测试。


DI:依赖注入,是一种软件设计模式,应DIP依赖倒置原则,描述组件之间高层组件不应该依赖于底层组件。依赖倒置是指实现和接口倒置,采用自顶向下的方式关注所需的底层组件接口,而不是其实现。其应用框架则为IOC,在.net中有很多我们熟悉的IOC框架,如Unity,Castle windsor,Ninject,Autofact等等,其常常分为构造注入,函数注入,属性注。同时在IOC和Service Locator(服务查找),如果你想更多的了解IOC和DI请参见martin fowler的​​Inversion of Control Containers and the Dependency Injection pattern​​。

回到angularjs:在框架中为我们提供了angular.injector(modules)DI注入注射器。但是在我们使用注入的时候常常是不需要关心具体的如何注入。我们只需要按照其规则书写我们的angularjs代码就会很容易的得到angularjs的DI特性,DI方式有三种:

angular提供了3种获取依赖的方式:inference、annotation、inline方式。

​​


1. // 创建myModule模块、注册服务  
2. var myModule = angular.module('myModule', []);
3. myModule.service('myService', function() {
4. this.my = 0;
5. });
6.
7. // 获取injector
8. var injector = angular.injector(["myModule"]);
9.
10. // 第一种inference
11. injector.invoke(function(myService){alert(myService.my);});
12.
13. // 第二种annotation
14. function explicit(serviceA) {alert(serviceA.my);};
15. explicit.$inject = ['myService'];
16. injector.invoke(explicit);
17.
18. // 第三种inline
19. injector.invoke(['myService', function(serviceA){alert(serviceA.my);}]);


其中 annotation和inline方式,对于函数参数名称没有要求,是推荐的做法;inference方式强制要求参数名称和服务名称一致,如果JS代码经过压缩或者混淆,那么功能会出问题,不建议使用这种方式。