在 Angular 中进行控制反转 (IoC)
Doing Inversion of Control (IoC) in Angular
假设我们有一个名为 MapService
的接口,以及两个实现:GoogleMapsService
和 LeafletMapService
。我想要一个包(或 Angular2?)来调用所需的实现而不是开发人员。
export interface MapService {
//define my API
}
@Injectable()
export class GoogleMapsService implements MapService {
//implement the API
}
这意味着,在组件中我希望服务的类型是接口(因此不依赖于实现):
import { Component } from '@angular/core';
import { MapService } from './map.service';
import { GoogleMapsService } from './google-maps.service';
@Component({
template : `...`,
providers: [GoogleMapsService]
})
export class MyComponent {
constructor(private googleMapsService : MapService) { //notice the type of the service here
}
}
我怎样才能做到这一点?
在提供程序数组中使用以下语法:
import { Component } from '@angular/core';
import { MapService } from './map.service';
import { GoogleMapsService } from './google-maps.service';
@Component({
template : `...`,
providers: [
{ provide: MapService, useClass: GoogleMapsService }
]
})
export class MyComponent {
constructor(private googleMapsService : MapService) {
}
}
请注意,您可以在模块范围内做同样的事情。
所以基于@jb-nizet 的精彩评论;我已经设法使用 InjectionToken 做我想做的事。这是一个代码片段:
import { Injectable, InjectionToken } from '@angular/core';
export const GOOGLE_MAPS_IMPL = new InjectionToken<MapService>('googleMapImpl');
export interface MapService {
//define the API
}
@Injectable()
export class GoogleMapsService implements MapService {
//implement the API
}
和组件:
import { Component, Inject } from '@angular/core';
import { MapService } from './map.service';
import { GoogleMapsService, GOOGLE_MAPS_IMPL } from './google-maps.service';
@Component({
template : `...`,
providers: [{ provide: GOOGLE_MAPS_IMPL, useClass: GoogleMapsService }]
})
export class MyComponent {
constructor(@Inject(GOOGLE_MAPS_IMPL) private googleMapsService : MapService) {
}
}
另一种解决方案是使用抽象 class 而不是接口。
export abstract class MapService{
// ...
}
让你的服务实现这个抽象class
并提供
import { Component } from '@angular/core';
import { MapService } from './map.service';
import { GoogleMapsService } from './google-maps.service';
@Component({
template : `...`,
providers: [
{ provide: MapService, useClass: GoogleMapsService }
]
})
export class MyComponent {
constructor(private googleMapsService : MapService) {
}
}
假设我们有一个名为 MapService
的接口,以及两个实现:GoogleMapsService
和 LeafletMapService
。我想要一个包(或 Angular2?)来调用所需的实现而不是开发人员。
export interface MapService {
//define my API
}
@Injectable()
export class GoogleMapsService implements MapService {
//implement the API
}
这意味着,在组件中我希望服务的类型是接口(因此不依赖于实现):
import { Component } from '@angular/core';
import { MapService } from './map.service';
import { GoogleMapsService } from './google-maps.service';
@Component({
template : `...`,
providers: [GoogleMapsService]
})
export class MyComponent {
constructor(private googleMapsService : MapService) { //notice the type of the service here
}
}
我怎样才能做到这一点?
在提供程序数组中使用以下语法:
import { Component } from '@angular/core';
import { MapService } from './map.service';
import { GoogleMapsService } from './google-maps.service';
@Component({
template : `...`,
providers: [
{ provide: MapService, useClass: GoogleMapsService }
]
})
export class MyComponent {
constructor(private googleMapsService : MapService) {
}
}
请注意,您可以在模块范围内做同样的事情。
所以基于@jb-nizet 的精彩评论;我已经设法使用 InjectionToken 做我想做的事。这是一个代码片段:
import { Injectable, InjectionToken } from '@angular/core';
export const GOOGLE_MAPS_IMPL = new InjectionToken<MapService>('googleMapImpl');
export interface MapService {
//define the API
}
@Injectable()
export class GoogleMapsService implements MapService {
//implement the API
}
和组件:
import { Component, Inject } from '@angular/core';
import { MapService } from './map.service';
import { GoogleMapsService, GOOGLE_MAPS_IMPL } from './google-maps.service';
@Component({
template : `...`,
providers: [{ provide: GOOGLE_MAPS_IMPL, useClass: GoogleMapsService }]
})
export class MyComponent {
constructor(@Inject(GOOGLE_MAPS_IMPL) private googleMapsService : MapService) {
}
}
另一种解决方案是使用抽象 class 而不是接口。
export abstract class MapService{
// ...
}
让你的服务实现这个抽象class 并提供
import { Component } from '@angular/core';
import { MapService } from './map.service';
import { GoogleMapsService } from './google-maps.service';
@Component({
template : `...`,
providers: [
{ provide: MapService, useClass: GoogleMapsService }
]
})
export class MyComponent {
constructor(private googleMapsService : MapService) {
}
}