NestJS 学习分享:从工厂模式到企业级后端开发

NestJS 学习分享:从工厂模式到企业级后端开发

NestJS 是一个基于 Node 的纯后端企业级开发框架 。它默认使用 TypeScript,奉行全面模块化的思想,非常适合用来构建企业级服务。下面结合我们的示例项目,把其中的核心概念梳理一遍。


一、后端开发到底在做些什么?

在动手写代码之前,先搞清楚后端开发的定位。后端开发主要做几类事情:

  • 提供 API 接口:做 Web 开发,给前端提供数据服务
  • 系统集成:处理并发、底层服务、AI Infra 等
  • 微服务:构建可拆分的服务架构

这些场景都需要一个稳定、可扩展的框架,而 NestJS 正是为此而生。


二、安装与目录结构

bash 复制代码
npm i -g @nestjs/cli   # 全局安装脚手架

nest new hello          # 创建项目
nest run start          # 启动项目

生成后的目录结构核心在 src 下:

markdown 复制代码
- src
  - main.ts          # 入口文件
  - app.module.ts    # 根模块

其中:

  • main.ts 是程序入口,负责启动应用
  • app.module.ts根模块,负责把各个业务模块组织起来

三、工厂模式(Factory Pattern)

3.1 设计模式的本质

设计模式是面向接口的编程 ,是抽象的。经典的设计模式一共有 23 种,工厂模式就是其中之一。

3.2 一个通俗的比喻

工厂模式可以这样理解:

你想喝奶茶,不用自己做(不要写流程代码 NO),直接找蜜雪冰城。 工厂?------柠檬水、圣代、芋圆......

在 NestJS 里,NestFactory 就相当于「蜜雪冰城」这个工厂,它满足我们创建 App 的各种需要。通过实现一个 MixueFactory,帮助我们提供工厂里的各种「类」,并且把这些五花八门的类解耦

开发者只需要一行:

lua 复制代码
MixueFactory.create(type);

就能拿到想要的产品。由于工厂里的每个类都实现了相同的 show 接口,所以由工厂生产出来的类,可以直接放心调用。

3.3 一个具体例子

下面是工厂模式的完整演示(factory_demo/1.mjs):

typescript 复制代码
// 蜜雪冰城产品之一 冰激凌
class IceCream {
  constructor() {
    this.name = '冰激凌';
    this.price = 3;
  }
  show() {
    console.log(`${this.name} 价格${this.price}`)
  }
}

class LeamonTea {
  constructor() {
    this.name = '柠檬水';
    this.price = 5;
  }
  show() {
    console.log(`${this.name} 价格${this.price}`)
  }
}

class MilkTea {
  constructor() {
    this.name = '珍珠奶茶';
    this.price = 8;
  }
  show() {
    console.log(`${this.name} 价格${this.price}`)
  }
}

// 工厂类
class MixueFactory {
  static create(type) {
    switch(type) {
      case 'ice':    return new IceCream();
      case 'leamon': return new LeamonTea();
      case 'milk':   return new MilkTea();
      default:       return null;
    }
  }
}

// 管理并返回冰激凌这个类
const drink1 = MixueFactory.create('ice');
drink1.show();
const drink2 = MixueFactory.create('leamon');
drink2.show();
const drink3 = MixueFactory.create('milk');
drink3.show();

这个例子的核心思想是:一个企业有很多产品,每一种产品都实现了相同的接口(方法) 。开发者不用记住工厂里那么多实现细节,只需要直接和工厂类打交道即可。


四、高度模块化与 MVC 架构

NestJS 采用高度模块化的约定:

kotlin 复制代码
App
 └── Modules
      ├── @nestjs/common 的 Module 类
      ├── import 依赖项
      ├── controller 控制器 ------ 参数校验、简单逻辑,最后 return response
      └── service 服务 ------ return 数据

4.1 MVC 的本质

main.ts 中的注释点明了 NestJS 的本质:

csharp 复制代码
// M Model 数据可抽象
// C Controller 控制器
// V View 视图
// 面向对象思想
// 工厂模式
const app = await NestFactory.create(AppModule);
await app.listen(process.env.PORT ?? 3000);
  • Model:数据可抽象
  • Controller:控制器,负责检测前端用户输入、做一些控制逻辑
  • View :视图层,不可以直接去数据库查数据

其中 NestFactory.create(AppModule) 就是工厂模式的体现------localhost:3000/ 的后端路由会被送到 AppModule,由它组织 controller 和 service 层,完成 CRUD 和 SQL 操作。

4.2 根模块 AppModule

less 复制代码
@Module({
  imports: [TodosModule],        // 依赖外界(导入其他模块)
  controllers: [AppController],  // 控制器:校验、简单逻辑
  providers: [AppService],       // data service:复杂业务
})
export class AppModule {}

根模块像一份「说明书」,照着做即可。它把三样东西组装在一起:

  • imports:引入依赖的外部模块
  • controllers:控制器列表
  • providers:服务(数据层)列表

4.3 开发流程总结

  1. AppModuleimport 里植入我们自己的 Module

  2. Module 是 NestJS 的独立业务模块,由三个文件定义:

    • xx.module.ts 定义、组装模块
    • xx.controller.ts 定义控制器
    • xx.service.ts 定义服务
  3. @Injectable() 实现自动依赖注入,自动注入到 controller 或任何使用它的地方

  4. controller 里的一个属性就能拿到 service 实例


五、装饰器模式(Decorator Pattern)

装饰器模式在不修改原有对象的前提下,动态地给对象叠加额外功能 。在 TypeScript 中,用 @ 加在 class 前面即可实现。

NestJS 把这个模式用到了极致,常见的装饰器有:

  • @Module():声明一个模块
  • @Controller('todos'):声明一个控制器,并指定路由前缀
  • @Injectable():把一个普通类变成 Nest 容器可管理的服务
  • @Get() / @Post() / @Put() / @Delete():声明 HTTP 请求方法
  • @Param('id') / @Body():提取请求参数和请求体

这些装饰器「快速地给类添加一些行为或方法」,正是 TypeScript 对装饰器的支持让这一切成为可能。


六、控制器与服务:各司其职

6.1 Service 层(数据与业务)

kotlin 复制代码
@Injectable()
export class AppService {
  // 给 controller 层一个交代
  getHello(): string {
    return 'hello world!';
  }
}

Service 层负责数据库业务、复杂业务 CRUD ,最后 return 数据 给 controller。

6.2 Controller 层(校验与调度)

less 复制代码
@Controller()
export class AppController {
  constructor(private readonly appService: AppService) {}

  @Get()
  getHello(): string {
    console.log('/ 的控制器');
    // 响应什么内容?交给 service 层
    // this -> Module
    return this.appService.getHello();
  }
}

Controller 层负责参数校验、简单逻辑,把真正的数据响应交给 service 层。

这里有一个关键点:controller 通过 constructor(private readonly appService: AppService) 拿到 service 实例,这是依赖注入 的结果,而不是 import 之后手动 new 实例化。


七、完整 CRUD 示例:Todos 模块

7.1 模块定义 todos.module.ts

kotlin 复制代码
@Module({
  controllers: [TodosController],
  providers: [TodosService],
})
export class TodosModule {}

这个文件负责「组装」,把控制器和服务绑定到这个业务模块里。

7.2 数据与类型 Todos.service.ts

typescript 复制代码
export interface Todo {
  id: number;
  title: string;
  completed: boolean;
}

let todos: Todo[] = [
  { id: 1, title: '学习 NestJS', completed: false },
  { id: 2, title: '学习 ', completed: false },
]

let nextId = 3;

@Injectable()
export class TodosService {
  findAll(): Todo[] {
    return todos;
  }
  findOne(id: number): Todo {
    const todo = todos.find(t => t.id === id);
    if(!todo) throw new NotFoundException(`Todo ${id} 不存在`);
    return todo;
  }
  create(title: string): Todo {
    const todo: Todo = {
      id: nextId++,
      title,
      completed: false
    }
    todos.push(todo);
    return todo;
  }
  remove(id: number): void {
    const index = todos.findIndex(t => t.id === id)
    if(index === -1) throw new NotFoundException(`Todo ${id} 不存在`);
    todos.splice(index, 1);
  }
  update(id: number, patch: Partial<Todo>): Todo {
    const todo = this.findOne(id);
    Object.assign(todo, patch);
    return todo;
  }
}

7.3 控制器 Todos.controller.ts

less 复制代码
@Controller('todos')
export class TodosController {
  constructor(private readonly todosService: TodosService) {}

  @Get()
  findAll(): Todo[] {
    console.log('/todos controller');
    return this.todosService.findAll();
  }

  @Get(':id')
  findOne(@Param('id') id: string): Todo {
    console.log(id);
    return this.todosService.findOne(Number(id));
  }

  @Post()
  create(@Body('title') title: string): Todo {
    return this.todosService.create(title);
  }

  @Delete(':id')
  remove(@Param('id') id: string): {message: string} {
    this.todosService.remove(Number(id));
    return {message: '删除成功'};
  }

  // Patch
  @Put(':id')
  update(
    @Param('id') id: string,
    @Body() patch: Partial<Todo>,
  ): Todo {
    return this.todosService.update(Number(id), patch);
  }
}

通过这个例子可以看到,一个业务模块完整地串起了 Module → Controller → Service 三层:路由到 controller,controller 校验参数后调用 service,service 处理数据后 return 回去。


八、错误处理:NotFoundException

后端业务讲究严谨稳定 ,需要一个「容错模块」。NestJS 提供了各种内置的错误类,用来标准化错误输出,例如:

javascript 复制代码
if(!todo) throw new NotFoundException(`Todo ${id} 不存在`);

NotFoundException 是 NestJS 内置的错误类。它让报错输出统一包含:

  • statusCode:状态码
  • message:消息

相比在 TypeScript 里到处写 try catch finally(线程挂掉的风险),NestJS 提供的错误类让错误处理更规范、更统一。


九、测试:控制器单元测试

NestJS 自带测试能力,示例项目里的 app.controller.spec.ts 演示了如何测试一个控制器:

ini 复制代码
describe('AppController', () => {
  let appController: AppController;

  beforeEach(async () => {
    const app: TestingModule = await Test.createTestingModule({
      controllers: [AppController],
      providers: [AppService],
    }).compile();

    appController = app.get<AppController>(AppController);
  });

  describe('root', () => {
    it('should return "Hello World!"', () => {
      expect(appController.getHello()).toBe('Hello World!');
    });
  });
});

@nestjs/testingTest.createTestingModule 可以创建一个独立的测试模块,注入需要的 controller 和 provider,然后验证返回值。


总结:重要知识回顾

知识点 核心内容
NestJS 定位 基于 Node 的纯后端企业级框架,默认 TypeScript,全面模块化
后端开发内容 提供 API 接口、系统集成(并发/底层/AI Infra)、微服务
工厂模式 面向接口编程,NestFactory.create(AppModule) 即工厂创建应用;产品类实现相同接口,调用方只需 Factory.create(type)
MVC 架构 Model(数据抽象)、Controller(校验/简单逻辑)、View(不直接查库);main.ts 启动,路由交给 AppModule 组织
模块化 @Module()imports / controllers / providers 组装模块,AppModule 是根模块
三层文件约定 xx.module.ts 组装、xx.controller.ts 控制器、xx.service.ts 服务
装饰器模式 不改原对象、动态叠加功能;@ + class@Module / @Controller / @Injectable / @Get / @Post / @Put / @Delete / @Param / @Body
依赖注入 @Injectable() 把普通类变成容器可管理服务,constructor 注入,无需手动 new
分层职责 Service 处理复杂业务 CRUD 并 return 数据;Controller 做校验/简单逻辑并 return response
错误处理 NotFoundException 等内置错误类,标准化输出 statusCode + message
测试 @nestjs/testingTest.createTestingModule 构建测试模块并验证返回值

一句话记住这套体系 :NestJS 用工厂模式 创建应用、用装饰器模式 给类加行为、用模块化 + MVC 组织代码,Controller 管输入校验、Service 管数据和业务、@Injectable 负责依赖注入、内置错误类负责标准化容错------最终形成一套稳定、可扩展的企业级后端开发方案。

相关推荐
vipbic2 小时前
网站升级了,我却有点舍不得
前端·vue.js·后端
IT_陈寒2 小时前
Java Stream并行处理让我数据库崩了两次
前端·人工智能·后端
2601_963870222 小时前
【计算机毕业设计】基于Spring Boot的考研信息交流平台的设计与实现
java·spring boot·后端
大模型丫丫2 小时前
Spring Boot 入门指南:从零开始构建你的第一个应用
java·spring boot·后端
卷无止境2 小时前
FastAPI的测试事件在测什么?
后端·python·fastapi
gis开发之家3 小时前
日志怎么打才专业?Spring Boot 4 日志体系与 Logback 配置(生产级实战)
java·spring boot·后端·logback
卷无止境3 小时前
FastAPI CLI 你需要认识这把命令行利器
后端·python·fastapi
AINative软件工程3 小时前
LLM 请求合并工程实践:用 Single-Flight 把并发重复调用从 N 次砍成 1 次
后端·llm·ai编程
程序员爱钓鱼3 小时前
Go 编程实战:数组 Array——固定长度的数据集合
后端·面试·go