概念

依赖注入是一种设计思想,并不是某一类语言所特有的,因此可以参考开涛大神关于学习Java语言的Spring框架时对其的解释:

DI—Dependency Injection,即“依赖注入”:是组件之间依赖关系由容器在运行期决定,形象的说,即由容器动态的将某个依赖关系注入到组件之中。依赖注入的目的并非为软件系统带来更多功能,而是为了提升组件重用的频率,并为系统搭建一个灵活、可扩展的平台。通过依赖注入机制,我们只需要通过简单的配置,而无需任何代码就可指定目标需要的资源,完成自身的业务逻辑,而不需要关心具体的资源来自何处,由谁实现。

理解DI的关键是:“谁依赖谁,为什么需要依赖,谁注入谁,注入了什么”,那我们来深入分析一下:

  • 谁依赖于谁:当然是应用程序依赖于IoC容器;
  • 为什么需要依赖:应用程序需要IoC容器来提供对象需要的外部资源;
  • 谁注入谁:很明显是IoC容器注入应用程序某个对象,应用程序依赖的对象;
  • 注入了什么:就是注入某个对象所需要的外部资源(包括对象、资源、常量数据)。

IoC和DI由什么关系呢?其实它们是同一个概念的不同角度描述,由于控制反转概念比较含糊(可能只是理解为容器控制对象这一个层面,很难让人想到谁来维护对象关系),所以2004年大师级人物Martin Fowler又给出了一个新的名字:“依赖注入”,相对IoC 而言,“依赖注入”明确描述了“被注入对象依赖IoC容器配置依赖对象”[1]

Angular中的依赖注入

Angular中可以在app.module.ts中进行全局声明,也可以在组件内部根据特定需求实现特定声明。

声明是通过属性providers实现的,顾名思义,它是一个对象提供者,复数形式表名其为数组形式。且子类型为Provide,它位于@angular/core中,实现如下:

export interface TypeProvider extends Type<any> {
}
export interface ValueProvider {
provide: any;
useValue: any;
multi?: boolean;
}
export interface ClassProvider {
provide: any;
useClass: Type<any>;
multi?: boolean;
}
export interface ExistingProvider {
provide: any;
useExisting: any;
multi?: boolean;
}
export interface FactoryProvider {
provide: any;
useFactory: Function;
deps?: any[];
multi?: boolean;
} export declare type Provider =
TypeProvider | ValueProvider | ClassProvider | ExistingProvider | FactoryProvider | any[];

可以看到,Provider共有5个明确的子类,也决定了其使用方式的数量。由于全局声明和组件内部声明的方式差别不大,可见的区别是在app.module.ts中属性providers是在模块注解@NgModule中声明而组件中是通过注解@Component声明。因此实现方式不对全局和组件加以区分。

由于是初学,此处仅列举常用的几种方式:useClassuseFactoryuseValue

useClass

providers: [{provide: DefaultBookService, useClass: DefaultBookService}]

其中provide定义了token,而useClass则指明了使用的类,此处由于token和实现类相同,均为DefaultBookService因此可以简写为providers: [DefaultBookService]

useFactory

   providers: [{
provide: DefaultBookService, useFactory: () => {
const rdm = Math.random() < 0.5;
if (rdm) {
return new DefaultBookService();
} else {
return new HuaZhangBookService();
}
}

HuaZhangBookServiceDefaulteBookService的一个子类。根据情况返回所需注入的对象。

如果通过依赖注入的对象同时依赖另一个通过依赖注入的对象应如何实现呢?比如DefaultBookService,它的构造函数为:

constructor(public logger: LoggerService) { },而LoggerService也是通过依赖注入-即不需要自己手工new LoggerService()-时应该怎么办?在类FactoryProvider中提供了一个名叫deps的参数,它可以帮助我们实现依赖对象的引用。用法如下:

   providers: [{
provide: DefaultBookService, useFactory: (logger: LoggerService) => {
const rdm = Math.random() < 0.5;
if (rdm) {
return new DefaultBookService(logger);
} else {
return new HuaZhangBookService(logger);
}
}, deps: [LoggerService]
}, LoggerService]

deps是一个任意类型的数组,为什么呢,因为类的参数不会只有一个,当构造方法中有多个参数时,可同时依赖多个不同类型的对象。

useValue

基本用法:

{provide: 'IS_DEV_ENV', useValue: Math.random() < 0.5}

扩展用法:

  providers: [{
provide: DefaultBookService, useFactory: (logger: LoggerService, isDev) => {
if (isDev) {
return new DefaultBookService(logger);
} else {
return new HuaZhangBookService(logger);
}
}, deps: [LoggerService, 'IS_DEV_ENV']
},
LoggerService, {provide: 'IS_DEV_ENV', useValue: Math.random() < 0.5}
]

可以看到,在useFactory的箭头表达式中有两个参数,他们依次对应deps中的token,即isDev对应token为IS_DEV_ENV的对象,而它正是使用了本小节中所涉及的useValue形式,它返回一个boolean对象。

另外需要注意的是,token不止能指定特定的类,也可以指定特定的值。

multi

参考

其他

  • 以上我们简单介绍了几种Angular实现依赖注入的方式,但是还需要提供使用它的条件,在Angular中,只有当组件或者服务被注解@Injectable或其子类如@Component修饰后,才可使用,建议无论是否使用依赖注入,都使用@Injectable修饰。
  • 可以通过构造方法的参数来放置通过依赖生成的对象:constructor(private bookService: DefaultBookService) { },此时,其他方法中直接使用this.bookService来调用DefaultBookService中的方法了。
  • 通过依赖注入传入的对象,可以通过Injector来进行访问,它位于@angular/core包中,因此上面的构造方法可以这样声明constructor(private injector: Injector) { },通过this.injector.get(DefaultBookService)来获取DefaultBookService对象并调用其中的方法,但不建议这样做,因为不如直接传入所需对象来的明确。
  • app.module.ts中使用useFactory并且使用箭头表达式来实现时,注册的组件会报错,至今无解,相关问题已发至segmentFault,哪位大神如果知道,烦请告诉,跪谢。
  • 关于Token的学习可以参考Angular 4 依赖注入教程之八 InjectToken的使用

  1. 如果想要更加深入的了解IoC和DI,请参考大师级人物Martin Fowler的一篇经典文章《Inversion of Control Containers and the Dependency Injection pattern》,原文地址:http://www.martinfowler.com/articles/injection.html。 ↩︎

Angular4学习笔记(四)- 依赖注入的更多相关文章

  1. SpringMVC:学习笔记(11)——依赖注入与@Autowired

    SpringMVC:学习笔记(11)——依赖注入与@Autowired 使用@Autowired 从Spring2.5开始,它引入了一种全新的依赖注入方式,即通过@Autowired注解.这个注解允许 ...

  2. Angular4.0从入门到实战打造在线竞拍网站学习笔记之三--依赖注入

    Angular4.0基础知识之组件 Angular4.0基础知识之路由 依赖注入(Dependency Injection) 正常情况下,我们写的代码应该是这样子的: let product = ne ...

  3. AngularJS学习笔记之依赖注入

    最近在看AngularJS权威指南,由于各种各样的原因(主要是因为我没有money,好讨厌的有木有......),于是我选择了网上下载电子版的(因为它不要钱,哈哈...),字体也蛮清晰的,总体效果还不 ...

  4. Spring.NET学习笔记6——依赖注入(应用篇)

    1. 谈到高级语言编程,我们就会联想到设计模式:谈到设计模式,我们就会说道怎么样解耦合.而Spring.NET的IoC容器其中的一种用途就是解耦合,其最经典的应用就是:依赖注入(Dependeny I ...

  5. Spring学习笔记——Spring依赖注入原理分析

    我们知道Spring的依赖注入有四种方式,各自是get/set方法注入.构造器注入.静态工厂方法注入.实例工厂方法注入 以下我们先分析下这几种注入方式 1.get/set方法注入 public cla ...

  6. Spring学习笔记1—依赖注入(构造器注入、set注入和注解注入)

    什么是依赖注入 在以前的java开发中,某个类中需要依赖其它类的方法时,通常是new一个依赖类再调用类实例的方法,这种方法耦合度太高并且不容易测试,spring提出了依赖注入的思想,即依赖类不由程序员 ...

  7. Unity学习笔记(4):依赖注入

    Unity具体实现依赖注入包含构造函数注入.属性注入.方法注入,所谓注入相当赋值,下面一个一个来介绍 1:构造函数注入 1.1当类有多个构造函数时,可以通过InjectionConstructor特性 ...

  8. angular2 学习笔记 ( DI 依赖注入 )

    refer : http://blog.thoughtram.io/angular/2016/09/15/angular-2-final-is-out.html ( search Dependency ...

  9. Asp.net core 学习笔记 ( DI 依赖注入 )

    比起 Angular 的依赖注入, core 的相对简单许多, 容易明白 所有 provider 都在 startup 里配置. public void ConfigureServices(IServ ...

  10. [学习笔记]Spring依赖注入

    依赖: 典型的企业应用程序不可能由单个对象(在spring中,也可称之bean)组成,再简单的应用也是由几个对象相互配合工作的,这一章主要介绍bean的定义以及bean之间的相互协作. 依赖注入: s ...

随机推荐

  1. 简单理解php深复制浅复制问题

    其实接触深复制浅复制是通过学习c++了解到的,比如c++很好用的模板,php是不允许方法模板和类模板 一个简单的例子,如果不是很了解php 的取地址符&,可以去看下官方文档,php的& ...

  2. centos6多实例安装mysql

    基本环境:setenforce 0service iptables stop yum install cmake libaio-devel ncurses-devel -yyum install gc ...

  3. TZOJ 3134: 渊子赛马修改版

    描述 赛马是一古老的游戏,早在公元前四世纪的中国,处在诸侯割据的状态,历史上称为“战国时期”.在魏国作官的孙膑,因为受到同僚庞涓的迫害,被齐国使臣救出后,到达齐国国都. 赛马是当时最受齐国贵族欢迎的娱 ...

  4. java之动态代理

    摘要 相比于静态代理,动态代理避免了开发人员编写各个繁锁的静态代理类,只需简单地指定一组接口及目标类对象就能动态的获得代理对象. 这里说的静态代理可以理解为之前使用的装饰者模式,从之前使用装饰者模式实 ...

  5. IO实时监控命令iostat详解

    iostat用于输出CPU和磁盘I/O相关的统计信息 命令格式 iostat [ -c ] [ -d ] [ -h ] [ -N ] [ -k | -m ] [ -t ] [ -V ] [ -x ] ...

  6. java中的key事件监听机制

    package com.at221; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import javax.sw ...

  7. linq 表分组后关联查询

    测试linq,获取有教师名额的学校.比如学校有5个教师名额,teacher数量没超过5个,发现有空额 var query = (from teacher in _repositoryTeacher.T ...

  8. Rocketmq源码导入eclipse时报错的解决方法

    1,Plugin execution not covered by lifecycle configuration: org.apache.maven.plugins:maven-help-plugi ...

  9. U盘安装各种系统方法总结

    一.软通牒(UltraISO) 1.安装系统CentOS-5.11-x86_64-bin-1to9 使用软通牒(UltraISO)打开CentOS-5.11-x86_64-bin-1of9.iso,启 ...

  10. noip单词接龙

    看了许多题解都好长啊,自不量力的来贴一下代码 (震惊于这都能ac...) 这道题的思路是先从字符串中找有重部分然后直接比较剩下的部分,比较的数据也可以用来计算数值 其实满水的题 总之看注释啦(竟然能耐 ...