假设我有两个模块,分别导出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 {}
但是关键是,我无法使用REQUEST
中的useFactory
(将其直接注入@nestjs/core
中),因为我在cron作业中和API调用中使用了此服务< / p>
我也不认为Factory
模式在那里有用,我的意思是它可以工作,但我想正确地进行操作
但是我不确定如何在我的情况下使用它
答案 0 :(得分:1)
如果属性是静态的(例如环境变量),则可以使用自定义提供程序来选择适当的实例。但是,如果该属性处于某种动态状态,则您不能完全依赖nest的依赖项注入,因为它会在启动时实例化提供程序(REQUEST作用域除外,这不是您的选择)。
创建一个custom provider,该实例基于静态属性(例如环境变量)实例化所需的实现。
{
provide: AService,
useClass: process.ENV.useBService ? BService : CService,
}
假设我们有两种不同的服务实现:
@Injectable()
export class BService {
public count = 0;
run() {
this.count++;
return 'B';
}
}
@Injectable()
export class CService {
public count = 0;
run() {
this.count++;
return 'C';
}
}
当两个变量count
的和为偶数时,应使用BService
; CService
奇怪的时候。为此,我们使用request scope创建一个自定义提供程序。
{
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],
},
如果我们的控制器现在注入MyService
令牌(@Inject('MyService')
)并通过端点公开其run
方法,它将返回B
C
{{1 }} ...
由于我们要使用默认范围(Singleton!),因此不能使用嵌套的依赖项注入的静态实例化。相反,您可以使用委托模式在根类(示例中为B
)中选择所需的实例。
按原样提供所有服务:
AService
在您的providers: [AService, BService, CService]
中动态决定要使用的实现方式:
AService
答案 1 :(得分:0)
我认为,工厂方法正是您所需要的。您描述了您需要基于上下文的其他服务,这对于工厂方法非常有用。让我们尝试一下:
创建可注射工厂:
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}"`);
}
}
}
现在将工厂导入到您的应用程序模块中:
import { ServiceFactory } from './ServiceFactory';
import { AService } from './AService';
@Module({
providers: [AppService, ServiceFactory]
})
export class AppModule {}
现在,您的应用程序服务将作为依赖项获得工厂,这将基于上下文创建适当的服务:
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();
}
}