**领域驱动设计 (DDD)**是开发代码库结构与业务领域结构非常匹配的软件的概念。

有关 DDD 的更多信息,您可以在此处找到它

我花了很多时间来理解和应用它到日常任务, 所以这篇文章是我的分享所有我所知道的关于 Ddd 。

ddd

规则

该规则规定,外圈中声明的某些>内圈不得在代码中提及。 —干净的建筑 - 鲍勃·—叔叔

依赖性是我们在软件开发中唯一无法避免的,因为组件/类要么使用另一个组件/类,要么被另一个组件/类使用。但是我们可以控制依赖的方向。

假设我们有一个链 A - > B - > C

  • A 取决于 B,B 取决于 C,然后 C 取决于 A。因此,如果 C 更改,B 必须更改,这导致 A 必须更改。我们称之为循环依赖,这总是一个不好的设计。
  • 我们可以通过依赖反转来控制这种依赖方向。添加额外的组件 A’, 我们有新的链 A - > B - > C, C - > A’, A - > A’ 。现在,一切都取决于A’。在这种情况下,C 可能会更改,A 可能会更改,但当 A’相同时,更改不会影响其他更改。
  • A’ 可能是 Java 语言上下文中的界面,也可以是模块级别的领域

各层角色

控制器层

  • 说明:表示请求的切入点。
  • 角色:
    • 中间件(请求验证、错误处理程序)。
    • 路由器。
    • 构建响应。

存储库层

  • 描述:对外部资源的呼叫请求(外部 API、数据库、消息队列…)。
  • 角色:
    • 外部 API 的中间件(请求验证、身份验证、错误处理程序)。
    • 管理 DB 连接。
    • 主营业务的外部逻辑之一。

应用层

  • 描述:包含编排/过程逻辑。
  • 角色:
    • 处理业务流程。
    • 拨打外部电话检索数据。

领域层

  • 描述:包含跨过程共享逻辑,主要侧重于特定领领域。
  • 角色:
    • 验证业务逻辑。
    • 实现业务逻辑。

理论太多了, 现在回到现实!!

如何将其应用于项目

让我们假设我们有一个业务流下面,这是关于预订一个座位在电影院:

  • IsInvestor:我们不想给购买者带来任何麻烦,所以如果他们要求一个座位,我们会替他们预定。
  • 资格:在此步骤中,我们将检查用户的年龄是否足够大。
  • 注册座位:为座位注册用户。
  • 通知:发送电子邮件,让他们知道请求是成功还是失败。

image

现在,我们根据上面的洋葱模型构建从外层到内层的代码库。

  • 控制器:此层处理 3 件事

    • 将路由器映射到控制器。
    • 验证请求所需的数据。
    • 应用程序层中获取合适的业务流程以处理此请求
  • 存储库:此层对外部服务提出请求。在这种情况下,我们可能需要来自下游用户的用户信息,来自座椅数据库的座位信息。

  • 应用程序:此层仅处理特定领域的业务逻辑,否则领域层将执行该工作。

    image

  • 领域:此层处理有关用户、座位和电子邮件服务的业务逻辑。这里有很多工作要做:

    • 从下游检索业务逻辑所需的数据。
    • 回报结果是购买者是否资格,等等。

毕竟代码库看起来会像:

├── controller
|  └── register-seat
|     ├── registerSeat.controller.ts
|     ├── registerSeat.router.ts
|     └── registerSeat.validator.ts
├── application
|  └── register-seat
|     └── registerSeatService.ts
├── repository
|  └── email
|  |  ├── type.ts
|  |  ├── emailBuilder.ts
|  |  └── emailService.ts
|  ├── user
|  |  ├── type.ts
|  |  └── userService.ts
|  └── seat
|     ├── type.ts
|     ├── seatSchema.ts
|     └── seatService.ts
└── domain
   ├── user
   |  └── eligibility
   |     ├── isSeatAvailable.ts
   |     └── isCurrentUserOldEnough.ts
   ├── email
   |  └── sendEmail.ts
   └── seat
      └── seatInfoProvider.ts

:子领域名可能与我的不同,取决于项目业务领域名。