DDD分层架构

11 min

:books: 前言

对比:MVC的开发模式:是数据驱动,自低向上的思想,关注数据。DDD的开发模式:是领域驱动,自顶向下,关注业务活动。

1. MVC融入DDD

结合DDD设计理念,完善dalbiz, controller, router架构

image-20240822163212742

:one: DAL

(数据接入层)

  • 现有角色: 负责数据的持久化操作,如数据库的CRUD(创建、读取、更新、删除)操作。
  • 在DDD中: 可以与基础设施层(Infrastructure Layer)对应。该层的接口定义应在领域层中,而具体实现则位于基础设施层。

:two: Domain

(领域层)

  • 引入领域层: 领域层是DDD(领域驱动设计)架构的核心,负责定义和实现核心业务逻辑和规则。领域层包含领域模型(实体、值对象、聚合、领域事件等)和领域服务。
    • 领域模型中的业务逻辑: 处理与核心业务逻辑和规则相关的操作,管理领域对象的状态和行为。领域模型的方法应专注于自身的职责,确保业务规则的一致性,而不涉及跨领域的应用逻辑。
      • 例如:在一个消息管理系统中,Message 实体可能会包含发送、接收、标记为已读等方法,这些方法只关心消息本身的行为和状态。

:three: Biz

**(业务层)**现有角色: 传统架构中,业务层通常处理应用层面的业务逻辑和业务规则,负责实现具体的用例。

  • DDD 中: 业务层通常可以重构为应用层(Application Layer)。应用层负责协调多个领域对象和领域服务,处理跨领域的业务流程。应用层不包含具体的业务规则,而是聚焦于 orchestrating(编排)领域对象的行为和实现应用任务或用例。
    • 应用层中的业务逻辑: 处理跨领域的逻辑,与用例相关,涉及多个领域对象之间的协作。例如,在处理消息发送时,应用层可能会调用用户验证服务、更新消息状态、触发领域事件、并记录操作日志等操作。
      • 例如:在一个消息系统中,应用层的 MessageService 可能会协调 UserMessage 等领域对象,检查用户权限、更新消息状态、发送通知等。

:four: Controller

(控制器层)

  • 现有角色: 处理客户端请求,将这些请求转发到相应的业务逻辑。
  • 在DDD中: 仍然是表现层(Presentation Layer)的一部分,负责将来自用户界面层的输入转换为应用层操作。

:five: Router

(路由层)

  • 现有角色: 定义URL路由,将请求指向合适的控制器。
  • 在DDD中: 继续作为表现层的一部分,负责请求的路由和映射。

2. Domain层详解

:white_flag: 概述

domain/
	├── dto/
	├── enum/
	├── model/
	└── vo/

1. DTO(数据传输对象)

Data Transfer Objects

  • 作用: DTO用于在不同系统组件或层之间传输数据,通常是简单的结构体,不包含业务逻辑。
  • 在领域层中的角色: 把数据传输的结构体定义在DTO中可以确保数据的一致性和类型安全。

2. Enum(枚举类型)

Enumerations

  • 作用: 枚举类型用于定义固定值的集合,确保代码的可读性和数据的合法性。
  • 在领域层中的角色:
    • 枚举可以用于描述领域中的特定状态或类别,例如消息类型、用户角色等。
    • 例如,event_bus.go 可能定义了事件类型的枚举,用于描述系统中不同类型的事件。
    • message.go 可能定义了消息的状态或类型。

3. Model(领域模型)

  • 作用: 领域模型是DDD的核心部分,包含了系统的业务实体和它们的行为。
  • 在领域层中的角色:
    • 状态和行为管理:
      • 领域实体(如message.go中的消息实体)管理自身的状态和行为。例如,Message实体可能包含方法来发送、接收、标记为已读等操作。
    • 业务规则:
      • 领域模型中实现的业务规则是与单个实体或聚合相关的。例如,消息实体可能有一个验证内容合法性的方法,或检查消息是否已过期。
    • 不可分割的操作:
      • 一些操作必须在实体内部完成,以保持领域的一致性。这些操作通常直接在领域模型中实现。

4. VO(值对象)

Value Objects

  • 作用: 值对象表示业务逻辑中一些不变的数据结构。它们用来传递数据,而不会改变这些数据的状态。
  • 在领域层中的角色:
    • 请求对象(Request Objects): req 目录下的文件,如 create_group_req.gouser_login_req.go,用于封装从外部传递到领域的操作请求。
    • 响应对象(Response Objects): resp 目录下的文件,如 message_resp.gouser_login_resp.go,用于封装从领域传递到外部的操作结果。

5. 领域层中的其他可能内容

除了你目前结构中已经包含的部分,领域层还可以包括

  • 领域服务(Domain Services): 当某个业务逻辑无法合理地归属到某个实体或值对象时,它就可以被抽取到领域服务中。领域服务是一个包含业务逻辑的独立类,不保存任何状态。
  • 仓储接口(Repositories): 用于定义如何持久化和检索领域对象,但具体的实现通常在基础设施层。

:rabbit2: 举例

domain/
│   // 领域层(Domain Layer),包含核心业务逻辑和实体。是DDD中的核心部分,负责处理业务逻辑。

├── dto/
│   // 数据传输对象(Data Transfer Objects,DTO),用于在不同的应用层之间传递数据。
│   ├── contact_dto.go         // 定义联系人相关的DTO,用于封装和传输联系人数据。
│   ├── delete_friend_dto.go   // 定义删除好友操作的DTO。
│   ├── group_dto.go           // 定义群组相关的DTO,如群组信息、成员等。
│   └── msg_dto.go             // 定义消息相关的DTO,传输消息内容和元数据。

├── enum/
│   // 枚举类型和常量(Enumerations),用于定义固定值集合,如事件类型、状态等。
│   ├── event_bus.go           // 事件总线相关的枚举,定义事件类型或通道。
│   ├── message.go             // 消息类型或状态的枚举定义。
│   ├── redis.go               // Redis相关的枚举或常量配置。
│   ├── redsync.go             // RedSync(分布式锁)的枚举或常量。
│   ├── rocketmq.go            // RocketMQ消息队列相关的枚举或常量。
│   └── room.go                // 房间(如聊天室)的相关枚举或常量。

├── model/
│   // 领域模型(Domain Model),定义核心业务实体及其行为。
│   └── message.go             // 消息实体的领域模型,定义消息的属性和行为。(即业务实现)

└── vo/
    // 值对象(Value Objects),用于表示领域中的一些值,通常是不可变的。
    ├── req/
    │   // 请求对象(Request Objects),封装从客户端传入的数据。
    │   ├── agree_friend_req.go         // 同意好友请求的VO。
    │   ├── create_group_req.go         // 创建群组请求的VO。
    │   ├── delete_friend_req.go        // 删除好友请求的VO。
    │   ├── delete_group_req.go         // 删除群组请求的VO。
    │   ├── get_group_member_list_req.go// 获取群组成员列表的VO。
    │   ├── get_message_list_req.go     // 获取消息列表的VO。
    │   ├── get_new_content_list_req.go // 获取新内容列表的VO。
    │   ├── get_new_msg_list_req.go     // 获取新消息列表的VO。
    │   ├── get_user_info_batch_req.go  // 批量获取用户信息的VO。
    │   ├── get_user_info_by_name_req.go// 通过名称获取用户信息的VO。
    │   ├── grant_administrator_req.go  // 授予管理员权限的VO。
    │   ├── is_friend_req.go            // 判断是否为好友的VO。
    │   ├── join_group_req.go           // 加入群组请求的VO。
    │   ├── message_req.go              // 消息请求的VO。
    │   ├── quit_group_req.go           // 退出群组请求的VO。
    │   ├── remove_administrator_req.go // 移除管理员权限的VO。
    │   ├── uid_req.go                  // 根据UID操作的VO。
    │   ├── user_apply_req.go           // 用户申请相关的VO。
    │   ├── user_login_req.go           // 用户登录请求的VO。
    │   └── user_register_req.go        // 用户注册请求的VO。

    └── resp/
        // 响应对象(Response Objects),封装从服务端返回的数据。
        ├── get_user_info_batch_resp.go // 批量获取用户信息的响应VO。
        ├── get_user_info_by_name_resp.go// 通过名称获取用户信息的响应VO。
        ├── message_resp.go             // 消息响应的VO。
        ├── page_list_resp.go           // 分页列表响应的VO。
        ├── pre_signed_resp.go          // 预签名的响应VO(可能用于文件上传等)。
        ├── user_apply_resp.go          // 用户申请的响应VO。
        ├── user_contact_resp.go        // 用户联系信息的响应VO。
        └── user_login_resp.go          // 用户登录响应的VO。