JavaScript中的整洁架构:实战掌握六边形架构

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

您的代码就是堡垒:为什么六边形架构能拯救您的JavaScript项目

\n\n

您是否曾遇到过这样的情况:更换数据库或替换外部API变成了一场重写半个项目的噩梦?或者,您编写的单元测试更像是集成测试,因为业务逻辑与Express或MongoDB紧密耦合?如果是这样——欢迎来到六边形架构(端口与适配器)的世界。

\n\n

这不仅仅是Alistair Cockburn书中的时髦模式。这是一种让您的JavaScript代码变得健壮、可测试且独立于框架的实用方法。在本文中,我们不会进行枯燥的讲解。我们将以一个真实任务(订单管理系统)为例,逐步按照JavaScript中的六边形架构原则构建它。您将看到业务逻辑如何保持纯净,而所有“噪音”(数据库、HTTP请求、队列)都被隔离在外。

\n\n

准备好了吗?开始吧!

\n\n

什么是六边形架构(端口与适配器是什么关系)?

\n\n

想象一艘宇宙飞船的闸门。内部是控制台(您的业务逻辑)。外部是无数不同的星球(数据库、Web框架、外部服务)。闸门就是端口(接口)。而让您在特定星球上呼吸的宇航服就是适配器。

\n\n

核心思想是:应用程序核心不应该知道谁在以及如何访问它。它只声明“端口”(接口)。而具体的实现(适配器)从外部接入。这带来了三大超能力:

\n\n
    \n
  • 业务逻辑隔离——更换数据库时无需触及折扣计算代码。
  • \n
  • 可测试性——无需启动Docker和真实数据库即可测试逻辑。
  • \n
  • 框架无关性——只需编写一个新适配器,即可从Express迁移到Fastify。
  • \n
\n\n

让我们进入代码部分。

\n\n

项目设置与文件夹结构

\n\n

首先,创建一个简单的结构。我们将使用纯TypeScript(或带JSDoc的JavaScript——随您方便)。我们的目标是构建一个订单管理系统。

\n\n
src/\n├── core/\n│   ├── domain/          # 实体和值对象\n│   ├── ports/           # 接口(端口)\n│   └── services/        # 业务逻辑(用例)\n├── adapters/\n│   ├── primary/         # 调用我们核心的适配器(HTTP、CLI)\n│   └── secondary/       # 核心调用的适配器(数据库、外部API)\n└── app.js               # 入口点(组装所有组件)\n
\n\n

步骤1. 核心:领域实体与端口

\n\n

从最重要的部分开始——不依赖任何东西的部分。创建Order(订单)实体。

\n\n

core/domain/Order.js

\n\n
export class Order {\n  constructor({ id, userId, items, status = 'pending' }) {\n    this.id = id;\n    this.userId = userId;\n    this.items = items; // 数组 { productId, quantity, price }\n    this.status = status;\n    this.total = this.calculateTotal();\n  }\n\n  calculateTotal() {\n    return this.items.reduce((sum, item) => sum + item.price * item.quantity, 0);\n  }\n\n  approve() {\n    if (this.status !== 'pending') {\n      throw new Error('Only pending orders can be approved');\n    }\n    this.status = 'approved';\n  }\n}\n
\n\n

现在定义端口——核心期望从外部世界获得的接口。

\n\n

core/ports/OrderRepository.js

\n\n
// 这是一个端口(接口)。我们不在这里实现它。\nexport class OrderRepository {\n  async save(order) { throw new Error('Not implemented'); }\n  async findById(id) { throw new Error('Not implemented'); }\n}\n
\n\n

core/ports/EmailService.js

\n\n
export class EmailService {\n  async sendOrderConfirmation(order) { throw new Err                

博客

书籍推荐