1. 什么是依赖注入(Dependency Injection)
依赖注入是一种设计模式,它允许我们将依赖项注入到一个类中,而不是在类中创建这些依赖项的实例。这样做带来的好处是:代码变得可测试、可维护并且更加灵活。在 Angular 中,依赖注入是一个非常重要的特性,因为我们经常需要在不同的组件和服务中共享代码。
下面是一个简单的例子,它展示了如何使用依赖注入来创建一个服务:
class LoggerService {
log(message: string) {
console.log(message);
}
}
class SomeComponent {
logger: LoggerService;
constructor(logger: LoggerService) {
this.logger = logger;
}
doSomething() {
this.logger.log('Something was done');
}
}
// 在启动应用程序之前,我们需要注册 LoggerService:
const logger = new LoggerService();
const someComponent = new SomeComponent(logger);
someComponent.doSomething();
在上面的代码中,我们创建了一个 LoggerService 类和一个 SomeComponent 类,并在 SomeComponent 构造函数中注入了 LoggerService。在 doSomething 方法中,我们使用 LoggerService 的实例来打印一条消息。
在注册 LoggerService 及创建 SomeComponent 实例之后,我们就可以执行 someComponent.doSomething() 方法了。当我们执行该方法时,它会调用 LoggerService 实例的 log 方法并打印一条消息。
2. Angular 中的依赖注入
在 Angular 应用程序中,我们也可以使用依赖注入来注入服务、管道、指令等等。在 Angular 的模块中,我们可以使用 providers 数组来注册服务,这样就可以在任何组件中访问该服务的实例。
2.1 为什么要使用依赖注入
在 Angular 中,我们通常使用依赖注入来完成以下任务:
降低耦合。依赖注入可以让我们将代码分离成更小更简洁的部分。
代码可测试性。如果一个组件依赖于服务,我们可以通过依赖注入一个 mock 服务来测试组件。
可维护性。将依赖项注入到类中可以使代码更加易于维护。如果我们需要更改一个服务的实现,只需要在模块中更改它的注册即可。
可重用性。可以使用依赖注入在多个组件之间共享代码。
2.2 在 Angular 中注入依赖
在 Angular 中,依赖注入是通过注入器(Injector)来实现的。注入器是一个对象,它负责创建、管理和销毁服务的实例。Angular 应用程序中的每个组件都有自己的注入器。当我们向组件中添加服务时,Angular 会自动创建该服务的实例并将实例注入到组件中。
最常见的方法是在组件的构造函数中注入服务,如下所示:
import { Component } from '@angular/core';
import { LoggerService } from './logger.service';
@Component({
selector: 'app',
template: `My App
`
})
export class AppComponent {
constructor(private logger: LoggerService) {
this.logger.log('App component created');
}
}
在上面的代码中,我们在 AppComponent 的构造函数中注入了一个 LoggerService 的实例。在构造函数中,我们可以访问该服务的所有方法和属性。我们可以通过将该服务标记为私有成员来避免将该服务直接暴露给组件。
2.3 在模块中注册服务
在 Angular 中,我们通常使用模块来组织我们的应用程序。我们可以在模块的 providers 数组中注册服务,在整个应用程序中都可以访问该服务的实例。下面是一个简单的例子,其中我们在 app.module.ts 中注册了一个 LoggerService:
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { LoggerService } from './logger.service';
@NgModule({
imports: [
BrowserModule
],
declarations: [
AppComponent
],
providers: [
LoggerService
],
bootstrap: [AppComponent]
})
export class AppModule { }
在上面的代码中,我们使用 providers 数组将 LoggerService 注册到 AppModule 中。现在,在整个应用程序中都可以使用 LoggerService 的实例了。
2.4 依赖注入的注解
在 Angular 中,我们使用注解来标记我们要注入的依赖项。常用的注解如下:
@Injectable:用于标记服务。
@Inject:用于指定要注入的实例。
@Optional:用于指定依赖项是可选的。
@Self:用于限制依赖项的搜索范围。仅在当前组件中搜索依赖项。
@Host:用于限制搜索范围。在当前组件及其祖先组件中搜索依赖项。
@SkipSelf:用于跳过当前组件的注入器。在当前组件的父级组件中搜索依赖项。
2.5 使用注入器手动创建服务的实例
有时候我们不希望使用依赖注入自动创建服务的实例,而是手动创建该实例。在这种情况下,我们可以使用注入器来手动创建服务的实例。下面是一个简单的例子,它展示了如何手动使用注入器创建服务的实例:
import { Component, Injector } from '@angular/core';
import { LoggerService } from './logger.service';
@Component({
selector: 'app',
template: `My App
`
})
export class AppComponent {
constructor(private injector: Injector) {
const logger = this.injector.get(LoggerService);
logger.log('App component created');
}
}
在上面的代码中,我们注入了 Injector 服务。在 AppComponent 的构造函数中,我们手动获取了 LoggerService 的实例,并使用实例的 log 方法打印一条消息。
3. 总结
依赖注入是 Angular 中非常重要的特性之一,在 Angular 中,依赖注入不仅仅可以用于服务,还可以用于管道、指令等等。使用依赖注入可以让我们的代码更加灵活、可测试、可维护,同时也提高了代码的可重用性。