NestJs:动态创建 Class 的实例

NestJs: Dynamically Create Instances of Class

我想在 NestJs 中动态创建 class 个实例,而不是单例。

我找到了两种方法:

1) 直接创建class(ChripSensor 不是@Injectable)

import { ChirpSensor } from './chirp-sensor/chirp-sensor';

@Injectable()
export class SensorsService {
  registeredSensors: any;
  constructor(
    @InjectModel('Sensor') private readonly sensorModel: Model<ISensor>,
    private i2cService: I2cService) {
       const sensors = this.i2cService.getSensors();
       sensors.forEach((sensor) => {this.registeredSensors[sensor._id] = new ChirpSensor({name: sensor.name})});

    }

我想知道这是否符合nest.js

的DI方式

2) 第二种解决方案是通过 factory,但这里我不知道如何传递选项。

export const chirpFactory = {
  provide: 'CHIRP_SENSOR',
  useFactory: (options) => {
    console.log('USING FACTORY CHIRP, options', options)
    if (process.env.SIMULATION === 'true') {
      return new ChirpSensorMock(options);
    }
    else {
      return new ChirpSensor(options);
    }
  }
};

不太确定如何在此处继续/正确注入工厂,因为示例在没有选项的情况下在构造函数中创建对象?

问题:

创建那些 class 个实例的 NestJs 方法是什么?

编辑 - B12Toastr

模块 - 在编译时获取 Mock 或 Original

providers: [
  {
    provide: 'CHIRP_SENSOR',
    useValue: process.env.SIMULATION === 'true'
      ? ChirpSensorMock
      : ChirpSensor
  },
],

传感器服务

@Injectable()
export class SensorsService {
  registeredSensors: any;
  constructor(
    @Inject('CHIRP_SENSOR') private ChirpSensorClass: any, // any works but ChirpSensorMock | ChirpSensor not
    private i2cService: I2cService
   ) {
    const sensors = this.i2cService.getSensors();
    sensors.forEach((sensor) => {this.registeredSensors[sensor._id] = new ChirpSensorClass({name: sensor.name})});

  }

您可以通过 DI 通过 useValue or useClass

将选项传递给您的工厂
providers: [
  {
    provide: MyOptions,
    useValue: options
  },
  {
    provide: 'CHIRP_SENSOR',
    useFactory: (options: MyOptions) => {
      console.log('USING FACTORY CHIRP, options', options);
      if (process.env.SIMULATION === 'true') {
        return new ChirpSensorMock(options);
      } else {
        return new ChirpSensor(options);
      }
    },
  },
],

或者,您也可以完全避免使用工厂,并通过 class 在编译时决定使用哪个工厂:

providers: [
  {
    provide: MyOptions,
    useValue: options
  },
  {
    provide: 'CHIRP_SENSOR',
    useValue: process.env.SIMULATION === 'true'
      ? ChirpSensorMock
      : ChirpSensor
  },
],

或者简单地说:

providers: [
  {
    provide: MyOptions,
    useValue: options
  },
  {
    process.env.SIMULATION === 'true' ? ChirpSensorMock : ChirpSensor
  },
],

如果您没有使用上述工厂,则可以使用典型的基于构造函数的依赖注入将选项注入 ChirpSensor(或模拟传感器):

@Injectable()
export class ChripSensor {
  constructor(@inject(MyOptions) private options: MyOptions) {
  }

  // ...
}

根据您的选项是包裹在 class 还是简单的对象中,您可以使用 useValueuseClass。使用 useClass 您必须编写更少的代码并且不必使用 @Inject 装饰器,因为 class 本身用作 DI 令牌。但是,如果 MyOptions 是 class,您似乎在任何情况下都不需要使用 @Inject 来注入依赖项,因为 NestJS 使用 class 作为 DI 令牌,无论您是否使用 useValueuseClass 来提供依赖...