摘要
从工厂模式与装饰器模式出发,解析NestJS模块化架构和Controller/Provider分层,理解依赖注入及TypeScript装饰器语法,打通设计模式到框架应用的全链路认知。
Node.js 的生态中,Express 和 Koa 是轻量级框架,适合快速搭建 API。但当项目规模增长到企业级------需要模块化、依赖注入、中间件编排、微服务支持时------NestJS 成为了更合理的选择。NestJS 默认使用 TypeScript,全面采用模块化思想,将后端开发从"写路由"升级为"设计架构"。
NestJS 在企业级开发中的定位
后端开发不仅仅是提供 API 接口。企业级后端涵盖系统集成、并发处理、底层服务、AI Infra 以及微服务架构。NestJS 的设计目标就是覆盖这些场景------它不是一个"写接口"的框架,而是一个"组织服务"的框架。
NestJS 的安装和初始化非常直接:
bash
npm i -g @nestjs/cli
nest new hello
nest run start
@nestjs/cli 是 NestJS 的命令行工具,负责项目脚手架搭建、模块生成、构建和运行。nest new hello 创建一个名为 hello 的项目,包含完整的目录结构。nest run start 启动开发服务器。
目录架构与模块化约定
一个 NestJS 项目的核心目录结构如下:
ruby
src/
├── main.ts # 入口文件,创建应用实例
├── app.module.ts # 根模块,声明应用的所有依赖
├── app.controller.ts
└── app.service.ts
main.ts 是应用的入口,使用 NestFactory.create() 创建 NestJS 应用实例并监听端口。app.module.ts 是根模块,是整个应用的"地图"------它声明了哪些控制器属于这个模块、哪些服务可以被注入、以及依赖了哪些其他模块。
NestJS 的模块化遵循一个清晰的约定:App → Modules → Controllers → Providers。每个模块是一个独立的业务单元,控制器负责接收请求和参数校验,提供者(通常是 Service)负责业务逻辑和数据返回。
模块化架构的三层结构
NestJS 的模块化基于 @nestjs/common 提供的 Module 类。每个模块通过 @Module() 装饰器声明,包含三个核心属性:
typescript
@Module({
imports: [], // 依赖的其他模块
controllers: [], // 该模块的控制器集合
providers: [], // 该模块的服务提供者集合
})
export class AppModule {}
imports 声明模块依赖------如果某个模块依赖于另一个模块的功能,就在 imports 中引入。controllers 注册该模块下的所有控制器,每个控制器负责处理一组相关的 HTTP 请求。providers 注册服务类,NestJS 会自动创建这些服务的实例并注入到需要的控制器中。
控制器负责请求入口------参数校验、输入验证、调用服务、返回响应。它的职责很薄,就像餐厅的前台,只负责点单和上菜,不负责做菜。
提供者负责业务逻辑------从数据库查询数据、调用外部 API、执行业务规则计算。它不关心 HTTP 请求来自哪里,只关心数据输入和输出。
这种分层让 Controller 和 Provider 各司其职,各自只关注自己的职责边界。
工厂模式:从蜜雪冰城看对象创建
NestJS 的依赖注入机制本质上就是工厂模式的实现。工厂模式的核心思想是:把对象的创建和使用分离。调用者不需要知道对象是如何创建的,只需要告诉工厂"我要什么",工厂返回"你要的"。
用蜜雪冰城的例子来理解工厂模式最直观。蜜雪冰城有多种产品------冰激凌 3 元、柠檬水 4 元、珍珠奶茶 5 元。每种产品实现了相同的接口(show() 方法),但具体的创建细节各不相同:
javascript
class IceCream {
constructor() {
this.name = '冰激凌';
this.price = 3;
}
show() {
console.log(`${this.name} ${this.price}元`);
}
}
class LemonTea {
constructor() {
this.name = '柠檬水';
this.price = 4;
}
show() {
console.log(`${this.name} ${this.price}元`);
}
}
class MilkTea {
constructor() {
this.name = '珍珠奶茶';
this.price = 5;
}
show() {
console.log(`${this.name} ${this.price}元`);
}
}
如果没有工厂,顾客需要知道所有类的存在------"我要 IceCream 类的实例"、"我要 LemonTea 类的实例"------这要求顾客了解类的内部细节。工厂模式把这个问题解决了:
javascript
class MixueFactory {
static create(type) {
switch (type) {
case 'ice':
return new IceCream();
case 'lemon':
return new LemonTea();
case 'milk':
return new MilkTea();
default:
return null;
}
}
}
const drink1 = MixueFactory.create('ice');
drink1.show(); // 冰激凌 3元
const drink2 = MixueFactory.create('lemon');
drink2.show(); // 柠檬水 4元
顾客只需要知道 MixueFactory.create('ice') 就能拿到冰激凌。工厂封装了所有产品的创建逻辑,调用者与具体类解耦。这就是工厂模式的核心价值。
NestJS 的依赖注入容器正是基于这个思想。开发者在 providers 中注册服务类,NestJS 的 IoC 容器(Inversion of Control 容器)在运行时自动创建这些类的实例,生命周期由容器管理。控制器不需要 new Service(),只需要在构造函数中声明依赖,NestJS 的"工厂"就会自动注入:
typescript
@Controller('users')
export class UsersController {
constructor(private readonly usersService: UsersService) {}
// usersService 由 NestJS 自动创建并注入
}
private readonly usersService: UsersService 声明了一个私有只读属性,TypeScript 会自动生成 this.usersService = usersService 的赋值代码。NestJS 的 IoC 容器在创建 UsersController 实例时,检测到它需要 UsersService,于是查找 providers 中注册的 UsersService 类,创建它的实例,然后注入到控制器中。
装饰器模式:动态增强行为
NestJS 中随处可见装饰器:@Module()、@Controller()、@Get()、@Post()、@Injectable()、@Inject()。装饰器模式允许在不修改原有对象的前提下,动态地给类添加行为或方法。
在 NestJS 中,装饰器的作用是元数据标注 。@Controller('users') 给类添加了"这是一个控制器,处理 /users 路径的请求"的元数据。@Get(':id') 给方法添加了"这是一个 GET 请求处理函数,路径参数为 id"的元数据。NestJS 在启动时扫描所有装饰器,收集这些元数据,构建路由映射表。
TypeScript 的装饰器语法让 NestJS 的代码非常声明式:
typescript
@Controller('users')
export class UsersController {
@Get(':id')
findOne(@Param('id') id: string) {
return this.usersService.findOne(id);
}
}
@Param('id') 从请求路径中提取 id 参数并直接注入到方法参数中。开发者不需要手动解析 req.params------装饰器代劳了。
装饰器模式与工厂模式在 NestJS 中协同工作:工厂模式(IoC 容器)负责对象的创建和注入,装饰器模式负责元数据的标注和路由映射。工厂管"谁依赖谁",装饰器管"谁处理什么"。
企业级后端开发的完整链路
从工程化的角度看,NestJS 的企业级开发链路包含多个层次:
- API 接口层:Controller 接收请求,参数校验,调用 Service
- 业务逻辑层:Service 处理核心业务,调用 Repository 或外部服务
- 数据访问层:与数据库交互,ORM(TypeORM、Prisma)管理实体关系
- 系统集成层:消息队列、缓存、第三方 API 集成
- 微服务层:使用 TCP、Redis、Kafka 等传输层实现服务间通信
NestJS 的模块化架构让这些层次可以独立演进。每个微服务是一个独立的 NestJS 应用,通过 @nestjs/microservices 实现服务间通信。每个模块通过 @Module() 的 imports 声明依赖关系,依赖关系清晰可查,不存在隐式的全局状态。
总结
NestJS 将后端开发从"写路由"升级为"设计架构"。工厂模式通过 IoC 容器实现了依赖注入------开发者只需要在 providers 中注册服务,NestJS 自动管理对象的创建和生命周期。装饰器模式通过 @Module()、@Controller() 等注解实现了元数据标注------路由映射、参数提取、依赖声明全部通过装饰器完成。
蜜雪冰城的 MixueFactory 让顾客不需要知道 IceCream 和 LemonTea 的创建细节,NestJS 的 IoC 容器让控制器不需要知道 Service 的创建细节。工厂模式管对象的创建,装饰器模式管元数据的标注------这两个设计模式构成了 NestJS 架构的基石。