hej*_*ooo 4 javascript dependency-injection node.js typescript nestjs
假设我有两个正在导出的模块,BService并且CService这两个服务都在其中扩展AService
所以代码看起来像这样:
abstract class AService {
public run() {}
}
@Injectable()
export class BService extends AService {}
@Injectable()
export class CService extends AService {}
@Module({
providers: [BService],
exports: [BService],
})
export class BModule {}
@Module({
providers: [CService],
exports: [CService],
})
export class CModule {}
@Injectable()
class AppService {
constructor(protected readonly service: AService) {}
public run(context: string) { // let's assume context may be B or C
this.service.run();
}
}
@Module({
imports: [CModule, BModule],
providers: [{
provide: AppService,
useFactory: () => {
return new AppService(); // how to use BService/CService depending on the context?
}
}]
})
export class AppModule {}
Run Code Online (Sandbox Code Playgroud)
但关键是,我不能使用REQUEST(直接注入useFactory) from@nestjs/core因为我在 cron 作业和 API 调用中使用此服务
我也不认为Factory模式在那里有用,我的意思是它会起作用,但我想正确地做
我在考虑基于属性的注入。
但我不确定如何在我的情况下使用它
如果属性是静态的(例如环境变量),您可以使用自定义提供程序来选择正确的实例。但是,如果该属性在某种程度上是动态的,则您不能仅仅依赖 Nest 的依赖注入,因为它会在启动时实例化提供程序(REQUEST 范围除外,这不适合您)。
创建一个自定义提供程序,根据静态属性(例如环境变量)实例化所需的实现。
{
provide: AService,
useClass: process.ENV.useBService ? BService : CService,
}
Run Code Online (Sandbox Code Playgroud)
假设我们有两种不同的服务实现:
@Injectable()
export class BService {
public count = 0;
run() {
this.count++;
return 'B';
}
}
@Injectable()
export class CService {
public count = 0;
run() {
this.count++;
return 'C';
}
}
Run Code Online (Sandbox Code Playgroud)
当count两者变量之和为偶数时,BService应使用 ;CService当它很奇怪的时候。为此,我们创建一个具有请求范围的自定义提供程序。
{
provide: 'MyService',
scope: Scope.REQUEST,
useFactory: (bService: BService, cService: CService) => {
if ((bService.count + cService.count) % 2 === 0) {
return bService;
} else {
return cService;
}
},
inject: [BService, CService],
},
Run Code Online (Sandbox Code Playgroud)
如果我们的控制器现在注入MyService令牌( )并通过端点@Inject('MyService')公开其方法,它将返回...runB C B
由于我们想使用默认作用域(Singleton!),因此无法使用 Nest 依赖注入的静态实例化。相反,您可以使用委托模式在根类中选择所需的实例(AService在您的示例中)。
按原样提供所有服务:
providers: [AService, BService, CService]
Run Code Online (Sandbox Code Playgroud)
动态决定AService要使用的实现:
@Injectable()
export class AService {
constructor(private bService: BService, private cService: CService) {}
run(dynamicProperty) {
if (dynamicProperty === 'BService') {
return this.bService.run();
} else {
return this.cService.run();
}
}
}
Run Code Online (Sandbox Code Playgroud)
在我看来,工厂方法正是您所需要的。您描述了您需要基于上下文的不同服务,这非常适合工厂方法。让我们试试这个:
创建一个可注入的工厂:
import { Injectable } from '@nestjs/common';
import { AService } from './AService';
import { BService } from './BService';
import { CService } from './CService';
@Injectable()
export class ServiceFactory {
public getService(context: string) : AService {
switch(context) {
case 'a': return new BService();
case 'b': return new CService();
default: throw new Error(`No service defined for the context: "${context}"`);
}
}
}
Run Code Online (Sandbox Code Playgroud)
现在将该工厂导入您的应用程序模块:
import { ServiceFactory } from './ServiceFactory';
import { AService } from './AService';
@Module({
providers: [AppService, ServiceFactory]
})
export class AppModule {}
Run Code Online (Sandbox Code Playgroud)
现在您的应用服务将获得工厂作为依赖项,它将根据上下文创建适当的服务:
import { ServiceFactory } from './ServiceFactory';
import { AService } from './AService';
@Injectable()
class AppService {
constructor(readonly serviceFactory: ServiceFactory) { }
public run(context: string) {
const service: AService = this.serviceFactory.getService(context);
service.run();
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
4066 次 |
| 最近记录: |