深入 NestJS:从工厂模式到装饰器模式的架构之美

NestJS 是一个用于构建高效、可靠且可扩展的服务端应用程序的框架,它完全使用 TypeScript 构建,并深受 Angular 的启发。它不仅是一个简单的 Web 框架,也是一套完整的后端开发解决方案。

NestJS 的核心架构:模块化与 MVC

在深入设计模式之前,我们先来了解 NestJS 的基本架构。它高度模块化,并遵循经典的 MVC(Model-View-Controller)思想,尽管在后端 API 开发中,View 层通常被 JSON 数据响应所取代。

一个典型的 NestJS 应用由以下几个核心部分组成:

  1. 模块 (Module) :使用 @Module() 装饰器定义,是组织应用程序结构的基本单元。一个模块可以将相关的控制器(Controllers)和提供者(Providers,如 Services)封装在一起。AppModule 是应用的根模块,NestJS 从这里开始构建应用依赖图。

    typescript

    编辑

    ts 复制代码
    // app.module.ts
    import { Module } from '@nestjs/common';
    import { AppController } from './app.controller';
    import { AppService } from './app.service';
    import { TodosModule } from './todos/Todos.module';
    
    @Module({
      imports: [TodosModule], // 导入其他模块
      controllers: [AppController], // 注册控制器
      providers: [AppService], // 注册服务
    })
    export class AppModule {}
  2. 控制器 (Controller) :使用 @Controller() 装饰器定义,负责处理传入的请求并返回响应。它接收客户端的请求,进行初步的参数校验和逻辑处理,然后将复杂的业务逻辑委托给服务层。

    typescript

    编辑

    ts 复制代码
    // app.controller.ts
    import { Controller, Get } from '@nestjs/common';
    import { AppService } from './app.service';
    
    @Controller()
    export class AppController {
      constructor(private readonly appService: AppService) {}
    
      @Get()
      getHello(): string {
        return this.appService.getHello();
      }
    }
  3. 提供者/服务 (Provider/Service) :使用 @Injectable() 装饰器定义,是 NestJS 中一个非常重要的概念。服务层封装了具体的业务逻辑,例如数据库操作(CRUD)、复杂的计算或与其他服务的交互。控制器通过依赖注入来使用服务。

    typescript

    编辑

    ts 复制代码
    // app.service.ts
    import { Injectable } from '@nestjs/common';
    
    @Injectable()
    export class AppService {
      getHello(): string {
        return 'Hello World!';
      }
    }
  4. 入口文件 (main.ts) :这是应用的起点。它使用 NestFactory 来创建一个 Nest 应用实例,并监听指定的端口。

    typescript

    编辑

    ts 复制代码
    // main.ts
    import { NestFactory } from '@nestjs/core';
    import { AppModule } from './app.module';
    
    async function bootstrap() {
      const app = await NestFactory.create(AppModule);
      await app.listen(3000);
    }
    bootstrap();

工厂模式:解耦对象创建的利器

工厂模式 是 NestJS 中最基础也是最重要的设计模式之一。它的核心思想是将对象的创建过程封装起来,使得客户端代码无需关心对象的具体创建细节,只需向"工厂"请求即可。

这就像你想喝奶茶,不需要自己去买茶叶、牛奶、糖然后一步步制作,而是直接去"蜜雪冰城"(工厂)点一杯。工厂会根据你的需求(参数)生产出你想要的奶茶(对象)。

在 NestJS 中,工厂模式的应用随处可见:

  • 应用实例的创建 :在 main.ts 中,NestFactory.create(AppModule) 就是一个典型的工厂方法。我们不需要知道 Nest 应用实例内部是如何被复杂地构建和配置的,只需要调用这个静态方法,就能得到一个 ready-to-use 的应用实例。
  • 依赖注入系统 :NestJS 的依赖注入(DI)容器本质上就是一个强大的工厂。当你在控制器的构造函数中声明 private readonly appService: AppService 时,NestJS 的 DI 容器(工厂)会自动为你创建或提供一个 AppService 的实例。你无需手动 new AppService(),这极大地降低了类与类之间的耦合度。

代码示例:一个简化的工厂模式

假设我们有一个 MixueFactory,它可以根据类型生产不同的饮品。

typescript

编辑

js 复制代码
// 抽象产品
interface Drink {
  show(): void;
}

// 具体产品
class MilkTea implements Drink {
  show() { console.log('这是一杯奶茶'); }
}
class LemonTea implements Drink {
  show() { console.log('这是一杯柠檬水'); }
}

// 工厂类
class MixueFactory {
  static create(type: string): Drink {
    if (type === 'milktea') {
      return new MilkTea();
    } else if (type === 'lemontea') {
      return new LemonTea();
    }
    throw new Error('未知饮品类型');
  }
}

// 客户端使用
const myDrink = MixueFactory.create('milktea');
myDrink.show(); // 输出: 这是一杯奶茶

通过这种方式,如果未来要增加一种新的饮品(例如咖啡),我们只需要添加新的产品类并修改工厂类,而所有调用 MixueFactory.create 的客户端代码都无需改动。这完美体现了"开闭原则"。

装饰器模式:为类动态添加"超能力"

装饰器模式是 NestJS 的灵魂,它让框架的声明式编程风格成为可能。装饰器是一种特殊类型的声明,它能够被附加到类声明、方法、访问符、属性或参数上。

它的核心作用是在不修改原始对象代码的前提下,动态地给对象添加额外的功能或元数据。你可以把它想象成给一个普通的蛋糕(类)加上奶油、水果和蜡烛(装饰器),让它变成一个生日蛋糕,而蛋糕本身还是那个蛋糕。

在 NestJS 中,装饰器被用到了极致,几乎所有的核心功能都通过装饰器来定义:

  • @Module() : 将一个类标记为模块,并提供元数据来组织应用的各个部分。
  • @Controller('todos') : 将一个类定义为控制器,并为其指定一个路由前缀(如 /todos)。
  • @Get(), @Post(), @Put(), @Delete() : 将这些装饰器附加到控制器的方法上,将其绑定到特定的 HTTP 请求方法和路径。
  • @Injectable() : 标记一个类可以被 NestJS 的依赖注入系统管理。
  • @Param(), @Body(), @Query() : 用于从 HTTP 请求中提取特定的数据,并自动注入到控制器方法的参数中。

代码示例:解析装饰器的魔力

让我们看一个 TodosController 的例子,来理解装饰器是如何工作的。

typescript

编辑

ts 复制代码
// Todos.controller.ts
import { Controller, Get, Post, Param, Body } from '@nestjs/common';
import { TodosService } from './Todos.service';

@Controller('todos') // 1. 定义基础路由为 /todos
export class TodosController {
  constructor(private readonly todosService: TodosService) {}

  @Get() // 2. 处理 GET 请求到 /todos
  findAll() {
    return this.todosService.findAll();
  }

  @Post() // 3. 处理 POST 请求到 /todos
  create(@Body('title') title: string) { // 4. 从请求体中提取 title 字段
    return this.todosService.create(title);
  }

  @Get(':id') // 5. 处理 GET 请求到 /todos/:id
  findOne(@Param('id') id: string) { // 6. 从路由参数中提取 id
    return this.todosService.findOne(Number(id));
  }
}
  • @Controller('todos') 告诉 NestJS,这个类是一个控制器,所有内部方法的路由都以 /todos 开头。
  • @Get() 告诉 NestJS,findAll 方法用来处理对 /todos 的 GET 请求。
  • @Body('title') 是一个参数装饰器,它自动从 POST 请求的 JSON 体中取出 title 字段的值,并传递给 create 方法。

如果没有装饰器,我们需要编写大量重复的、命令式的代码来手动注册路由、解析请求对象,代码会变得非常冗长和难以维护。装饰器模式让代码变得极其简洁、清晰和声明式,开发者可以更专注于业务逻辑本身。

总结

NestJS 的强大之处在于它巧妙地运用了经典的设计模式来构建一个优雅、健壮且易于维护的框架。

  • 工厂模式 通过 NestFactory 和依赖注入系统,实现了对象的创建与使用的解耦,让代码结构更清晰,更易于测试和管理。
  • 装饰器模式作为框架的基石,提供了声明式的元数据,极大地简化了路由、依赖注入等核心功能的配置,让开发者能够以一种非常直观的方式来构建复杂的后端应用。

理解这两种模式,是掌握 NestJS 精髓的关键一步。

相关推荐
HjhIron5 小时前
NestJS 入门指南:从工厂模式到模块化 CRUD 实战
前端·nestjs
凌涘5 小时前
NestJS 的模块化后端组织方式
nestjs
小林ixn8 小时前
NestJS 入门实战:从 0 到 1 撸一个 Todo CRUD,感受装饰器与模块化的优雅
后端·mvc·nestjs
烬羽9 小时前
NestJS 依赖注入:Controller 里那个没有 new 的 service,到底从哪来的?
设计模式·typescript·nestjs
渣波9 小时前
NestJS 企业级后端架构实战:从核心代码到工程化思维的深度重构
前端·typescript·nestjs
不好听6139 小时前
NestJS 是什么?一张图看懂企业级后端的骨架
后端·nestjs
嘟嘟07179 小时前
NestJS 入门:从 NestFactory 入口到 Module/Controller/Service 模块化结构一次讲清
typescript·node.js·nestjs
用户9385156350720 小时前
工厂模式与 Nest.js 核心思想 —— 从蜜雪冰城到企业级架构
后端·设计模式·nestjs
用户9385156350720 小时前
实战 Todo CRUD —— 从路由到异常,手写一个完整模块
后端·typescript·nestjs