You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在NestJS中正确使用工厂模式?两种实现方案求鉴

问题

我在NestJS中实现了两种基于工厂模式的动态模块方案,不确定哪种才是正确用法:

方案一:直接通过useFactory返回对应驱动服务

该方案未设置专属服务,而是根据配置返回对应驱动服务,但会导致DriverService1与DriverService2被一同实例化:

export const createFactory = (config: IConfig): Provider<IService> => {
    return {
        provide: 'FACTORY',
        useFactory: (service1: DriverService1, service2: DriverService2): IService => {
            if (config.driver == 'DriverService1') {
                return service1;
            } else if (config.driver == 'DriverService2') {
                return service2;
            }
            throw new Error('not implemented')
        },
        inject: [DriverService1, DriverService2],
    }
};

@Module({})
export class MyModule {
    static register(config?: IConfig): DynamicModule {
        const factory = createFactory(config)
        return {
            module: MyModule,
            providers: [
                {
                    provide: 'CONFIG',
                    useValue: config,
                },
                DriverService1,
                DriverService2,
                factory
            ],
            exports: [factory],
        };
    }
}

方案二:通过专属服务内部实现工厂模式

创建专属服务MyModuleService,在服务内部管理驱动实例,仅在需要时实例化对应驱动:

interface IDriver {
    action1(): void
    action2(): void
    action3(): void
}

class Driver1 implements IDriver {
    public action1(): void {
        console.log("DriverService1 action1")
    }
    public action2(): void {
        console.log("DriverService1 action2")
    }
    public action3(): void {
        console.log("DriverService1 action3")
    }
}

class Driver2 implements IDriver {
    public action1(): void {
        console.log("DriverService2 action1")
    }
    public action2(): void {
        console.log("DriverService2 action2")
    }
    public action3(): void {
        console.log("DriverService2 action3")
    }
}


export const createFactory = (config: IConfig): Provider<MyModuleSerice> => {
    return {
        provide: 'BROKER_FACTORY',
        useFactory: (service: MyModuleSerice): MyModuleSerice => {
            if (config.driver == 'Driver1') {
                service.setDriver(new Driver1());
            } else if (config.driver == 'Driver2') {
                service.setDriver(new Driver2());
            } else {
                throw new Error('not implemented')
            }
            return service
        },
        inject: [MyModuleSerice],
    }
};


@Module({})
export class MyModule {
    static register(config?: IConfig): DynamicModule {
        const factory = createFactory(config)
        return {
            module: MyModule,
            providers: [
                {
                    provide: 'CONFIG',
                    useValue: config,
                },
                factory
            ],
            exports: [factory],
        };
    }
}

@Injectable()
class MyModuleSerice {
    protected driver: IDriver
    constructor() {
    }

    public setDriver(driver: IDriver) {
        this.driver = driver
    }
    
    public doSomething(): void {
        this.driver.action1()
        this.driver.action2()
    }

    public doSomething2(): void {
        this.driver.action1()
        this.driver.action3()
    }
}

请问哪种实现方式才是NestJS中工厂模式的正确用法?


分析与结论

两种方案都符合NestJS语法规范,但适用场景不同,需根据实际需求选择:

方案一的优劣势

  • 优势:逻辑直接,依赖注入容器自动管理驱动服务的生命周期,若驱动本身依赖其他NestJS服务(带@Injectable装饰的类),能自动完成注入。
  • 劣势:无论配置选哪个驱动,所有驱动服务都会在模块初始化时被实例化,若驱动初始化成本高(比如建立外部连接),会造成不必要的资源浪费。

方案二的优劣势

  • 优势:仅实例化配置指定的驱动,避免资源冗余;通过专属服务封装驱动逻辑,对外暴露统一业务方法(如doSomething),调用方无需感知具体驱动实现,符合封装原则。
  • 劣势:若驱动需要依赖NestJS其他服务,手动new Driver1()的方式无法利用依赖注入容器,需额外处理依赖传递;专属服务增加了一层封装,逻辑相对复杂。

推荐用法

如果你的驱动服务是无状态、初始化成本低的类,方案一简单直接,可直接使用;

如果驱动服务初始化成本高,或者需要对外提供统一的业务接口,推荐方案二,但可以优化驱动实例化方式:将驱动类标记为@Injectable(),通过依赖注入获取实例而非手动new,示例修改如下:

useFactory: (service: MyModuleSerice, driver1: Driver1, driver2: Driver2): MyModuleSerice => {
    if (config.driver == 'Driver1') {
        service.setDriver(driver1);
    } else if (config.driver == 'Driver2') {
        service.setDriver(driver2);
    } else {
        throw new Error('not implemented')
    }
    return service
},
inject: [MyModuleSerice, Driver1, Driver2],

同时在模块providers中注册Driver1和Driver2,结合@Optional()装饰器或动态注册逻辑,确保仅实例化需要的驱动。

另外,更符合NestJS最佳实践的方式是利用自定义提供者的useClass动态注册,直接根据配置添加对应驱动提供者,避免实例化未使用的服务:

@Module({})
export class MyModule {
    static register(config?: IConfig): DynamicModule {
        const driverProvider = {
            provide: 'DRIVER',
            useClass: config.driver === 'DriverService1' ? DriverService1 : DriverService2,
        };
        return {
            module: MyModule,
            providers: [
                { provide: 'CONFIG', useValue: config },
                driverProvider,
                {
                    provide: 'FACTORY',
                    useFactory: (driver: IService) => driver,
                    inject: ['DRIVER'],
                }
            ],
            exports: ['FACTORY'],
        };
    }
}

这种方式只会实例化配置指定的驱动,同时保留依赖注入的优势,逻辑简洁高效。

内容的提问来源于stack exchange,提问作者user192344

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 13:50:26