动态查找服务实现
Look up service implementations dynamically
我们的 Angular 应用程序有一个可以有不同实现的服务,又名。 “策略”。为简单起见,我们假设它是一个“事件报告”服务。事件上报服务具有上报信息的功能。根据运行时偏好,报告可以关闭,转到 console
,或发送到 REST API,或转到其他地方。
使用纯 TS,这看起来像:
interface IReporter {
report (message: string): void;
}
class NoReporter implements IReporter {
report (message: string): void {
// no op.
}
}
class ConsoleReporter implements IReporter {
report (message: string): void {
console.log(message);
}
}
// etc.
在消费者中,我会放置一些工厂来提供所需的记者,例如基于用户偏好设置:
getReporter (key: string): IReporter {
switch (key) {
// … tedious cases, which need to be mainted. Yikes!
}
}
然而,这感觉不太像“Angular”。第一步可能是为个别记者提供适当的 Angular 服务,但仅此一点感觉收获不大。所以:是否有一些现有机制可以让我获得上述工厂功能来动态查找实现?有任何可遵循的模式、示例或最佳实践吗?
如评论中所述FactoryProviders完美解决此问题
您必须将 IReporter
接口定义为 class interface,因为接口在运行时不存在,因此它们不是有效的 DI 令牌:
export abstract class IReporter {
report: (message: string) => void;
}
@Injectable()
export class NoReporter implements IReporter{
report(message:string):void{
}
}
@Injectable()
export class ConsoleReporter implements IReporter {
report(message: string): void {
console.log(message);
}
}
现在您可以创建 reporterFactory
和 reporterProvider
,如下所示:
const reporterFactory = (key: string) => {
switch (key) {
case 'no-report':
return () => new NoReporter();
case 'console-report':
return () => new ConsoleReporter();
default:
return () => new ConsoleReporter();
}
};
export const reporterProvider = (key: string) => {
return {
provide: IReporter,
useFactory: reporterFactory(key)
}
};
并在你的组件中注入一个记者:
@Component({
selector: 'test',
template: `TESTCOMPONENT`,
providers: [
reporterProvider('console-report')
]
})
export class TestComponent {
constructor(private reporter: IReporter) {
reporter.report('it works!!!');
}
}
我们的 Angular 应用程序有一个可以有不同实现的服务,又名。 “策略”。为简单起见,我们假设它是一个“事件报告”服务。事件上报服务具有上报信息的功能。根据运行时偏好,报告可以关闭,转到 console
,或发送到 REST API,或转到其他地方。
使用纯 TS,这看起来像:
interface IReporter {
report (message: string): void;
}
class NoReporter implements IReporter {
report (message: string): void {
// no op.
}
}
class ConsoleReporter implements IReporter {
report (message: string): void {
console.log(message);
}
}
// etc.
在消费者中,我会放置一些工厂来提供所需的记者,例如基于用户偏好设置:
getReporter (key: string): IReporter {
switch (key) {
// … tedious cases, which need to be mainted. Yikes!
}
}
然而,这感觉不太像“Angular”。第一步可能是为个别记者提供适当的 Angular 服务,但仅此一点感觉收获不大。所以:是否有一些现有机制可以让我获得上述工厂功能来动态查找实现?有任何可遵循的模式、示例或最佳实践吗?
如评论中所述FactoryProviders完美解决此问题
您必须将 IReporter
接口定义为 class interface,因为接口在运行时不存在,因此它们不是有效的 DI 令牌:
export abstract class IReporter {
report: (message: string) => void;
}
@Injectable()
export class NoReporter implements IReporter{
report(message:string):void{
}
}
@Injectable()
export class ConsoleReporter implements IReporter {
report(message: string): void {
console.log(message);
}
}
现在您可以创建 reporterFactory
和 reporterProvider
,如下所示:
const reporterFactory = (key: string) => {
switch (key) {
case 'no-report':
return () => new NoReporter();
case 'console-report':
return () => new ConsoleReporter();
default:
return () => new ConsoleReporter();
}
};
export const reporterProvider = (key: string) => {
return {
provide: IReporter,
useFactory: reporterFactory(key)
}
};
并在你的组件中注入一个记者:
@Component({
selector: 'test',
template: `TESTCOMPONENT`,
providers: [
reporterProvider('console-report')
]
})
export class TestComponent {
constructor(private reporter: IReporter) {
reporter.report('it works!!!');
}
}