DDD 领域驱动设计入门
973 字
5 分钟
DDD 领域驱动设计入门
DDD(Domain-Driven Design,领域驱动设计) 不是一种框架,而是一种面向复杂业务系统的软件设计方法论。
它的核心思想是:
软件结构应该围绕业务领域(Domain)组织,而不是围绕数据库、接口、框架组织。
为什么会有 DDD
很多项目一开始都是这样:
controllerservicerepositorymodel例如:
user_controller.gouser_service.gouser_repo.go当业务简单时没问题。
但随着需求增加:
用户订单支付优惠券库存物流积分Service 会越来越大:
func CreateOrder() { 检查库存 检查优惠券 扣减库存 创建订单 创建支付单 发MQ}最后:
OrderService3000行业务规则散落在:
- Controller
- Service
- SQL
- MQ Consumer
维护起来很痛苦。
DDD 就是为了解决:
复杂业务逻辑如何长期演进。
DDD 的核心概念
1. Domain(领域)
领域就是业务范围。
例如电商:
电商系统├── 用户领域├── 订单领域├── 支付领域├── 库存领域└── 物流领域每个领域独立思考。
“这个东西如果脱离 HTTP、数据库、缓存、消息队列,仍然有业务意义吗?”
- 如果有,可能属于 domain
- 如果没有,多半不属于 domain
2. Entity(实体)
有唯一身份的对象。
例如:
type User struct { ID int64 Name string}即使名字变了:
张三 → 李四还是同一个用户。
因为:
ID没变3. Value Object(值对象)
没有身份。
只关心值。
例如:
type Money struct { Amount int64 Currency string}两个:
100 CNY100 CNY就是相等的。
4. Aggregate(聚合)
DDD最重要概念之一。
例如订单:
Order├── OrderItem├── Address└── PaymentInfo这些对象一起维护一致性。
形成:
Order Aggregate聚合根(Aggregate Root)
外部只能访问:
Order不能直接改:
OrderItem例如:
order.AddItem(...)而不是:
order.Items[0].Count++这样业务规则集中。
Repository
Repository 不是 DAO。
DAO:
db.Create(...)Repository:
type OrderRepository interface { Save(order *Order) FindByID(id string)}领域层不知道:
MySQLPostgreSQLRedisDomain Service
有些业务不属于某个实体。
例如:
订单创建需要:
库存优惠券支付放进 Order 也不合适。
这时:
type OrderDomainService struct {}负责跨聚合逻辑。
Application Service
很多人容易混淆。
DDD里通常:
Controller ↓Application Service ↓Domain ↓RepositoryApplication Service:
负责:
- 编排流程
- 事务
- 调用领域对象
例如:
func CreateOrder(cmd CreateOrderCommand) { order := domain.NewOrder()
order.AddItem(...)
repo.Save(order)
mq.Publish(...)}分层架构
经典 DDD:
┌──────────────────┐│ Presentation ││ Controller/API │└────────┬─────────┘ ▼┌──────────────────┐│ Application ││ Use Case │└────────┬─────────┘ ▼┌──────────────────┐│ Domain ││ Entity ││ Aggregate ││ Domain Service │└────────┬─────────┘ ▼┌──────────────────┐│ Infrastructure ││ DB MQ Redis │└──────────────────┘Go 项目常见目录
internal/
├── application│ └── order│ └── service.go
├── domain│ └── order│ ├── entity.go│ ├── repository.go│ └── service.go
├── infrastructure│ └── repository│ └── order_repo.go
└── interfaces └── http └── order_handler.go在微服务里怎么用
假设你之前说的在线判题系统:
gatewayuserproblemjudgesandbox每个微服务都可以有自己的领域。
例如:
problem-service
ProblemTagSubmissionRulejudge-service
SubmissionJudgeTaskJudgeResultuser-service
UserRolePermissionDDD 和 MVC 的区别
MVC:
Controller ↓Service ↓DAO关注:
代码分层DDD:
Domain ↓Aggregate ↓Business Rules关注:
业务建模所以:
MVC 是技术视角,DDD 是业务视角。
两者并不冲突。
什么时候值得引入 DDD
如果是学习性质的:
GatewayUserProblemJudgeSandbox我的建议是:
第一阶段
普通三层:
handlerservicerepo先把功能跑通。
第二阶段
当出现:
提交代码↓创建Submission↓发MQ↓Judge消费↓更新结果↓更新排行榜这种复杂业务流时,
再引入:
AggregateDomain ServiceRepository会更容易体会 DDD 的价值。
否则很容易变成:
为了DDD而DDD写了很多目录和接口,但业务复杂度还没到那个程度。对于一个在线判题系统这类项目,比较合适的路线通常是:
三层架构 ↓理解微服务 ↓事件驱动(MQ) ↓DDD Lite ↓完整DDD这样学习曲线会平滑很多,也更符合实际项目的演进过程。
文章分享
如果这篇文章对你有帮助,欢迎分享给更多人!
相关文章智能推荐
1
Kubernetes 集群架构总览
云原生与运维K8s 集群的控制平面组件(apiserver/etcd/scheduler/controller-manager)与节点组件(kubelet/kube-proxy)。
2
Docker 镜像的分层与构建
云原生与运维Docker 镜像的分层结构、UnionFS 与构建缓存机制,以及 docker build 的多种用法。
3
微服务之间如何传递 trace
后端开发跨服务传递的是 trace 上下文而非 tracer:HTTP header、gRPC metadata 与 MQ 消息头的标准做法。
4
一致性哈希:consistent 与 rendezvous 的对比
后端开发两种分布式哈希的均匀度与耗时对比结论:节点少选 rendezvous,节点多且时间敏感选 consistent。
5
微服务鉴权与网关职责
后端开发Gateway 负责认证、Service 负责授权:身份上下文透传、反例风险与文件服务落地场景。
随机文章随机推荐











