接前一篇文章,针对一个接口或抽象类有多个实现的场景,除了使用useClass解决外,还可以使用useFactory来解决,看下面列子
person.module.ts
export interface Person {
id: number;
name: string;
email: string;
}
person.service.ts
import { Injectable } from '@nestjs/common';
import { Person } from './person';
export abstract class PersonService {
abstract findAll(): Promise<Person[]> ;
abstract findOne(id: number): Promise<Person> ;
}
export class RealPersonService extends PersonService {
persons: Person[] = [];
constructor() {
super();
this.persons = [
{ id: 1, name: 'John.real', email: 'john@example.com' },
{ id: 2, name: 'Jane.real', email: 'jane@example.com' },
{ id: 3, name: 'Bob.real', email: 'bob@example.com' },
];
}
async findAll(): Promise<Person[]> {
return this.persons;
}
async findOne(id: number): Promise<Person> {
const persons = this.persons.filter((person) => person.id == id);
return persons[0];
}
}
export class MockPersonService extends PersonService {
persons: Person[] = [];
constructor() {
super();
this.persons = [
{ id: 1, name: 'John.mock', email: 'john@example.com' },
{ id: 2, name: 'Jane.mock', email: 'jane@example.com' },
{ id: 3, name: 'Bob.mock', email: 'bob@example.com' },
];
}
async findAll(): Promise<Person[]> {
return this.persons;
}
async findOne(id: number): Promise<Person> {
const persons = this.persons.filter((person) => person.id == id);
return persons[0];
}
}
@Injectable()
export class EnvUtils {
isDevelopment() {
return process.env.NODE_ENV === 'development';
}
isProduction() {
return process.env.NODE_ENV === 'production';
}
}
- 这里抽象类PersonService定义了要提供的方法(这里之所以没有使用Interface是为了在module里配置的时候可以写类名,如果是Interface的话provider是不能写类的;
- 另外提供了两个实例类,一个real实现,一个mock实现,为了简单只是修改其中person.name的值;
- 这里还定义了一个工具类,用来获取环境变量,判断运行场景;
person.controller.ts
import {
Controller,
Get,
Param,
} from '@nestjs/common';
import { Person } from './person';
import { PersonService } from './person.service';
@Controller('persons')
export class PersonController {
constructor(private readonly personService: PersonService) {}
@Get()
async findAll(): Promise<Person[]> {
return this.personService.findAll();
}
@Get(':id')
async findOne(@Param('id') id: number): Promise<Person> {
return this.personService.findOne(id);
}
}
- 控制类简单注入了PersonService类;
person.module.ts
import { Inject, Module } from '@nestjs/common';
import { PersonController } from './person.controller';
import { PersonService, RealPersonService, MockPersonService, EnvUtils } from './person.service'
const PersonServiceProvider = {
provide: PersonService,
useFactory: (envUtils: EnvUtils) => {
if (envUtils.isDevelopment()) return new MockPersonService();
else if(envUtils.isProduction()) new RealPersonService();
else throw new Error('Invalid environment');
},
inject: [EnvUtils]
}
@Module({
controllers: [PersonController],
providers: [PersonServiceProvider, EnvUtils],
})
export class PersonModule {}
- module类定义了一个PersonServiceProvider,其中使用useFactory来根据环境变量来决定使用具体那个PersonService的实现类;
- 作为列子,这里useFactory也依赖了一个注入对象,此时可以使用inject注入进来;
测试
export NODE_ENV=development && npm run start:dev
或者
export NODE_ENV=production && npm run start:dev