DDD 理论
本文最后更新于72 天前,其中的信息可能已经过时,如有错误请发送邮件到 2915475627@qq.com

DDD相关概念

设计手段:战略设计,战术设计

领域建模:领域内实体,聚合根,值对象

领域服务

应用服务

充血模型:对象,服务

仓储,适配器


设计手段

战略设计是设计模块和边界,战术设计是详细设计实现。在官方推荐中,战略设计所有元素必不可少,战术设计可以根据项目复杂度自由裁剪。如果项目太简单可以不用过度设计。

战略设计

对复杂业务分治,微服务拆分服务,但拆太细会导致大量跨服务调用,反而退化为分布式单体。规定界限上下文,对于统一概念对象,在不同上下文中,可能有不同结构,需要详细区分。

战术设计

相较于扁平的 MVC 三层架构,贫血模型,使用 领域建模充血模型。设计领域服务和应用服务。

界限上下文:

模型只在某个明确边界内成立,超出边界应重新定义。


领域建模

属于 DDD 的战术设计,包含对象建模和领域服务。


对象建模

对象建模,涉及概念有实体,聚合根,值对象。

实体:

由唯一标识,状态属性,动作构成。

值对象:

具有不可变性,可替换性。

聚合根:

把实体和值对象作为一个整体,外部仅通过整体访问,这个整体叫做聚合根,构建整体的过程叫做聚合。聚合的作用是维护事务一致性边界,边界内部要强一致性,边界外可以最终一致性。外部想要访问实体或值对象必须通过聚合根,统一外部访问入口。


领域服务

领域服务处于聚合的边界外,如没有特殊要求,一般采用最终一致性。这也是聚合划分的重要依据。同时不宜做得太长,原因是在应用层编排的时候,中间可能会想加钩子。

好的工程实践:

只做「一个完整、不可分割的领域行为」,通常 ≤ 3 个聚合,不超过一个业务语义节点。


应用服务

不属于领域建模,但是放在这里展开说明,方便区分。

在六边形架构中,领域对象和领域服务都放在 /domain ,应用服务放在 /application 。应用服务负责编排领域服务,领域事件,仓储。应用层还会做事务管理,安全控制,幂等性校验等工程细节。

领域事件就是领域服务里说的钩子,是通过事件发布订阅实现的。


充血模型体现

领域对象

使对象充血,把对象功能方法提取到内部。但是一般提供给聚合根再由外部访问。

举例:

比如说一个对象会有功能,拼接缓存键,对其缓存进行 CRUD。拼接缓存键的方法应该放在对象内部,然后提供给外部,不然不同服务需要做拼接缓存键的方法,那就会在内部重新实现。


领域服务

当逻辑不该放在某个实体上时,应该放在领域服务里。

这其实是充血模型思想的延伸

  • 不是一切都要塞进 Entity
  • 无状态、跨聚合、有领域语义 → Domain Service
  • 区别于 Application Service(编排 / 用例)

举例:

有一个场景是用户A给用户B转账。

正确做法:

  1. Account 只做“自己的钱怎么变”(充血),基础演示简化省略聚合,主要体现充血方法。
class Account {
    private Money balance;

    public void deposit(Money amount) {
        balance = balance.add(amount);
    }
}
  1. 转账逻辑 → Domain Service
class TransferService {
    public void transfer(
            Account from,
            Account to,
            Money amount) {

        from.withdraw(amount);
        to.deposit(amount);
    }
}
  1. 应用层(Application Service)负责事务 & 编排
class TransferAppService {
    @Transactional
    public void transfer(String fromId, String toId, Money money) {
        Account from = accountRepo.load(fromId);
        Account to   = accountRepo.load(toId);

        transferService.transfer(from, to, money);

        accountRepo.save(from);
        accountRepo.save(to);
    }
}

错误示例:

accountA.transferTo(accountB, money);

Account 现在要知道并操作另一个 Account,破坏聚合边界,事务责任不清(谁先谁后?失败回滚谁?)

一个聚合根不应直接修改另一个聚合根的内部状态

accountService.transfer(aId, bId, money);

直接访问里实体属性,这是贫血模型 + Service 编排,不是 DDD。


聚合根

对于实体和值对象的操作,应该有聚合根操作。

order.confirm(paymentInfo);   // ✅ 行为在对象内
order.setStatus("CONFIRMED"); // ❌ 贫血


仓储,适配器

在领域层写仓储接口,基础设施层写适配器,符合依赖倒置原则。项目启动时,Spring框架会根据依赖自动注入。

1️⃣ 领域层只关心“能力”

public interface OrderRepository {
    Order find(OrderId id);
    void save(Order order);
}

2️⃣ Infrastructure 层“适配”它

@Repository
public class JpaOrderRepository implements OrderRepository {

    private final SpringDataOrderJpaRepository jpa;

    public Order find(OrderId id) {
        return jpa.findById(id.value())
                 .map(OrderMapper::toDomain)
                 .orElseThrow(...);
    }
}

拓展:

适配器不仅可以是数据库,缓存,还可以是 http,JSON,Token。


DDD 四色建模

目的

用面向对象的思想来设计,拆分现界上下文


四色建模过程

用户通过 决策命令,走 业务流程,完成 领域事件。领域事件触发 外部系统

决策命令:触发条件

业务流程:一般指那些领域服务

领域事件:代表事情的完成,用过去时态描述

外部系统:由于事件的完成触发

一个业务流程可以触发多个领域事件。


举例:

场景:一个人受媳妇委托去超市买东西,自己想买包烟。

媳妇发出买东西的决策命令。行为人到超市,推了一辆购物车,这是业务流程,购物车为实体。行为人往购物车里装东西,这是业务流程。购物车被装满,这是领域事件。行为人买了一包烟,买烟是业务流程,烟被买完是领域事件。


战略设计

产品诉求

设定一个抽奖系统。用户通过签到获得积分。消耗积分抽奖获得奖品。随着抽奖次数增加,奖池会升级。运营可以通过后台配置抽奖策略,奖品库存。


用例图

说明用户和行为关系,比较简单,仅作为蓝图。有助于领域建模


领域建模

对于识别出来的用例,用四色模型进行建模。


进行领域划分,这一步是明确领域边界。

仅抽象领域边界,忽略四色建模元素。


DDD 架构设计

核心技术功能

功能开发常用涉及点


MVC架构图

使用MVC包管理下的技术点


DDD架构图

使用DDD包管理下的技术点

1.简洁分包


2.六边形架构


领域设计

少领域设计分包 VS 多领域设计分包


领域建模

文末附加内容
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇