【问题标题】:NestJs: Dynamically Create Instances of ClassNestJs:动态创建类的实例
【发布时间】:2020-06-22 08:05:02
【问题描述】:

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

我找到了两种方法:

1) 直接创建类(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);
    }
  }
};

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

问题:

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})});

  }

【问题讨论】:

    标签: dependency-injection factory nestjs


    【解决方案1】:

    您可以通过useValueuseClass 将选项传递给您的工厂

    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);
          }
        },
      },
    ],
    

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

    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) {
      }
    
      // ...
    }
    

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

    【讨论】:

    • 在第二种情况下:process.env.SIMULATION === 'true' ? ChirpSensorMock : ChirpSensor 如果我在我的服务中通过 DI 使用它,我将如何传递选项?还是我会导入工厂,然后在构造函数之外调用工厂?我的意思是您能否在SensorsService 中添加如何使用该解决方案。
    • 我的意思是 options 仍然传递给 ChirpSensorMock 或 ChirpSensor 并且可能通过另一个服务检索,如第一个示例所示。
    • 我猜可能是useClass
    • 嗨@AndiGiga,是的,您将使用 DI 传递选项,如第一个示例中所示,我将其添加到代码中以进行澄清,并在我的答案底部进一步详细说明。根据您是否将选项包装在类中,您可以将选项提供为基于类的服务(使用useClass)或简单对象或其他类型(useValue)。
    • 我在上面做了一个编辑。由于选项是动态的并且是从 i2cService 检索的,因此我在上面用您的解决方案做了一个示例。我认为它现在有效,但仅适用于anytype。也许你有任何关于如何处理类型的建议。我得到This expression is not constructable. Type 'ChirpSensorMock' has no construct signatures.
    猜你喜欢
    • 2022-07-27
    • 2015-12-17
    • 2020-05-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多