【问题标题】:Implementing strategy in nest.js在 Nest.js 中实现策略
【发布时间】:2021-07-16 22:41:25
【问题描述】:

我正在尝试对服务使用策略模式,但是我尝试用作策略上下文的模块似乎只坚持两者之一。下面是示例代码:

animal.module.ts

@Module({})
export class AnimalModule {
    static register(strategy): DynamicModule {
        return {
            module: AnimalModule,
            providers: [{ provide: 'STRATEGY', useValue: strategy }, AnimalService],
            imports: [],
            exports: [AnimalService]
        };
    }
}

animal.service.ts

@Injectable()
export class AnimalService {
    constructor (@Inject('STRATEGY') private strategy) {
        this.strategy = strategy
    }

    public makeSound() {
        return this.strategy.makeSound()
    }
}

cat.module.ts

@Module({
    imports: [
        AnimalModule.register(catStrategy),
    ],
    controllers: [CatController],
    providers: [CatService],
})
export class CatModule {}

cat.service.ts

@Injectable()
export class CatService {
    constructor(
        private readonly animalService: AnimalService,
    ) {}

    public makeSound() {
        return this.animalService.makeSound()
    }
}

dog.module.ts

@Module({
    imports: [
        AnimalModule.register(dogStrategy),
    ],
    controllers: [DogController],
    providers: [DogService],
})
export class DogModule {}

dog.service.ts

@Injectable()
export class DogService {
    constructor(
        private readonly animalService: AnimalService,
    ) {}

    public makeSound() {
        return this.animalService.makeSound()
    }
}

cat.strategy.ts

class CatStrategy {
    public makeSound() {
        return 'meow';
    }
}

export const catStrategy = new CatStrategy();

复制问题的回购:https://github.com/kunukmak/nestjs-strategy-problem-example

为了澄清,在这种情况下 catService.makeSound 和 dogService.makeSound 都返回“喵”。可以让狗叫吗?

【问题讨论】:

    标签: dependency-injection singleton nestjs strategy-pattern


    【解决方案1】:

    我认为您正在寻找类似以下的内容。检查 repo 以获取完整示例 here。您可以在下面看到,我们正在从 AnimalModule 类注册一个 DynamicModule:

    @Module({
        imports: [AnimalModule.register()],
        controllers: [AppController],
        providers: [AppService],
    })
    export class AppModule {}
    

    register() 调用返回的 DynamicModule 负责确定要提供的 AnimalModule 的实现。这意味着我们可以根据环境中的配置自定义 AnimalModule。

    @Module({})
    export class AnimalModule {
        public static register(): DynamicModule {
            const AnimalClassProvider = AnimalModule.getClassProvider();
            return {
                module: AnimalModule,
                controllers: [AnimalController],
                providers: [AnimalClassProvider],
                exports: [AnimalClassProvider],
            };
        }
    
        private static getClassProvider(): ClassProvider<AnimalService> {
            const animalStrategy = process.env.ANIMAL_STRATEGY as AnimalStrategy;
            const AnimalServiceClass = AnimalModule.getClassFromStrategy(animalStrategy);
            return {
                provide: AnimalService,
                useClass: AnimalServiceClass,
            };
        }
    
        private static getClassFromStrategy(strategy: AnimalStrategy): Type<AnimalService> {
            switch (strategy) {
                case AnimalStrategy.CAT: return CatService;
                case AnimalStrategy.DOG: return DogService;
                default: return AnimalService;
            }
        }
    }
    

    在这种情况下,AnimalStrategy 只是一个枚举,用于确定我们应该提供哪种服务实现。

    通过这种方法,我们允许 Nest 正确地构造 Provider 及其所有依赖项。我们只负责告诉 Nest 在遇到 AnimalService 依赖项时将构建哪个实现。这允许我们应用程序的其余部分不知道实现,而只使用我们的 AnimalService 抽象。

    来自我们的 AnimalController:

    @Controller('animal')
    export class AnimalController {
        constructor(private readonly animalService: AnimalService) {}
    
        @Post()
        create(@Body() createAnimalDto: CreateAnimalDto) {
            return this.animalService.create(createAnimalDto);
        }
    
        // ...
    }
    

    到我们应用程序中的另一个服务:

    @Injectable()
    export class PetOwnerService {
        constructor(
            private readonly animalService: AnimalService,
            private readonly petOwnerService: PetOwnerService,
        ) {}
    
        feedPet(petName: string) {
            const petIsHungry = this.petOwnerService.isPetHungry(petName);
            if (petIsHungry) this.animalService.feed(petName);
            // ... 
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2021-08-10
      • 2012-04-16
      • 1970-01-01
      • 2021-09-11
      • 2021-11-16
      • 1970-01-01
      • 1970-01-01
      • 2014-10-18
      相关资源
      最近更新 更多