DDD分层架构
11 min
:books: 前言
对比:
MVC的开发模式:是数据驱动,自低向上的思想,关注数据。DDD的开发模式:是领域驱动,自顶向下,关注业务活动。
1. MVC融入DDD
结合
DDD设计理念,完善dal,biz,controller,router架构

:one: DAL
(数据接入层)
- 现有角色: 负责数据的持久化操作,如数据库的CRUD(创建、读取、更新、删除)操作。
- 在DDD中: 可以与基础设施层(Infrastructure Layer)对应。该层的接口定义应在领域层中,而具体实现则位于基础设施层。
:two: Domain
(领域层)
- 引入领域层: 领域层是DDD(领域驱动设计)架构的核心,负责定义和实现核心业务逻辑和规则。领域层包含领域模型(实体、值对象、聚合、领域事件等)和领域服务。
- 领域模型中的业务逻辑: 处理与核心业务逻辑和规则相关的操作,管理领域对象的状态和行为。领域模型的方法应专注于自身的职责,确保业务规则的一致性,而不涉及跨领域的应用逻辑。
- 例如:在一个消息管理系统中,
Message实体可能会包含发送、接收、标记为已读等方法,这些方法只关心消息本身的行为和状态。
- 例如:在一个消息管理系统中,
- 领域模型中的业务逻辑: 处理与核心业务逻辑和规则相关的操作,管理领域对象的状态和行为。领域模型的方法应专注于自身的职责,确保业务规则的一致性,而不涉及跨领域的应用逻辑。
:three: Biz
**(业务层)**现有角色: 传统架构中,业务层通常处理应用层面的业务逻辑和业务规则,负责实现具体的用例。
- 在
DDD中: 业务层通常可以重构为应用层(Application Layer)。应用层负责协调多个领域对象和领域服务,处理跨领域的业务流程。应用层不包含具体的业务规则,而是聚焦于 orchestrating(编排)领域对象的行为和实现应用任务或用例。- 应用层中的业务逻辑: 处理跨领域的逻辑,与用例相关,涉及多个领域对象之间的协作。例如,在处理消息发送时,应用层可能会调用用户验证服务、更新消息状态、触发领域事件、并记录操作日志等操作。
- 例如:在一个消息系统中,应用层的
MessageService可能会协调User、Message等领域对象,检查用户权限、更新消息状态、发送通知等。
- 例如:在一个消息系统中,应用层的
- 应用层中的业务逻辑: 处理跨领域的逻辑,与用例相关,涉及多个领域对象之间的协作。例如,在处理消息发送时,应用层可能会调用用户验证服务、更新消息状态、触发领域事件、并记录操作日志等操作。
: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.go、user_login_req.go,用于封装从外部传递到领域的操作请求。 - 响应对象(Response Objects):
resp目录下的文件,如message_resp.go、user_login_resp.go,用于封装从领域传递到外部的操作结果。
- 请求对象(Request Objects):
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。