文章目录

  • DDD领域驱动设计笔记
  • 贫血模型的优点和缺点
  • 领域模型的特点
  • 领域驱动设计概念
  • 领域模型
  • 通用语言:避免鸡同鸭讲
  • DDD分层架构
  • 在领域层有什么东西?
  • 实体(Entity)
  • 值对象(Value Object)
  • 领域服务
  • 聚合
  • 重建已经存储的领域对象:资源库
  • 总结
  • DDD是一套原则和模式,主要聚焦设计
  • DDD构造块
  • DDD获取成功的条件


贫血模型的优点和缺点

  • 简单
  • 对于只有少量业务逻辑的应用来说,使用起来非常自然
  • 开发迅速,易于理解
  • 注意:不能完全排斥这种方式
  • 无法良好的应对复杂逻辑
  • 例如:收入确认规则发生变化

领域模型的特点

  • 对业务领域做了建模
  • 细粒度的类,易于扩展,容易复用
  • 可以应对复杂的业务逻辑
  • 需要经验才能掌握
  • 简单的领域模型
  • 几乎和数据库中的表一一对应
  • 复杂领域模型
  • 使用了继承、组合、设计模式等各种手段

领域驱动设计概念

  • Domain Driven Design
  • DDD是一种以领域为核心的设计和开发理念。
  • DDD通过维护一个深度反应领域概念的模型,以及提供了可行的经过实践检验的大量模式来应对领域的复杂性

领域模型

  • 不是一个具体的图,而是那个图要传递的思想
  • 不是领域专家头脑中的知识,而是一个经过严格组织并选择性抽象的知识
  • 一幅图能够描绘和传达一个模型,同样,经过精心编写的代码和一段英语句子都能达到这个目的
  • 不是要建立一个尽可能符合“现实”的模型

通用语言:避免鸡同鸭讲

  • 领域专家(业务专家)必须要参与到模型的建立中来
  • 但是用谁的语言来沟通?
  • 专家有自己的行话
  • 技术人员有自己的黑话
  • 需要有一种通用语言,让团队在交流时能达到一致。

DDD分层架构

层级

作用

用户界面/展现层

负责向用户展现信息以及解释用户命令

应用层

很薄的一层,用来协调应用的活动。它不包含业务逻辑。它不保留业务对象的状态,但它保有应用任务的进度状态。(相当于贫血模型中的Service层,但是在领域模型中,该层级不实现业务逻辑,只调用领域层中的方法)

领域层

本层包含关于领域的信息。这是业务软件的核心所在。在这里保留业务对象的状态,对业务对象和它们状态的持久化被委托给了基础设施层。

基础设施层

本层作为其它层的支撑库存在。它提供了层间的通信,实现对业务对象的持久化,包含对用户界面层的支撑库等作用。

在领域层有什么东西?

实体(Entity)

  • 对象不是由属性定义的,而是标志定义的
  • 对象内容的变化不会影响标识符
  • 无论保存到硬盘、装入内存、通过网络发送,标识符都不变
  • 除了标识外,哪些东西应该成为实体的属性?
  • 抓住实体对象定义的最基本特征,用于识别、查找或匹配对象的特征
  • 只添加那些对概念至关重要的行为和这些行为所需的属性

值对象(Value Object)

  • 对象是根据值来确定的
  • 可以在不同实体中使用
  • 值对象通常是不可变的
  • Color/Point/Money/Address

领域服务

  • 有些领域逻辑是动词,表示了一种重要的行为很难映射为对象,无法归结到实体和值对象当中
  • 例如:转账
  • 特征
  • 服务执行的操作涉及一个领域概念,这个领域概念通常不属于一个实体或值对象
  • 被执行的操作涉及到领域中的其他对象
  • 操作是无状态的
  • 将Service划分到各个层中

层级

功能

应用层

资金转账应用服务

获取输入(例如json请求)

发送消息给领域层服务,要求其执行

监听转账的确认消息

使用基础设施服务来发送通知

领域层

** 资金转账领域服务**

与必要的账户对象进行交互,执行相应的介入和贷出操作

提供结果的确认(成功、失败等)

基础设施层

发送通知服务

发送电子邮件

聚合

  • 聚合概念
  • 聚合表示逻辑上联系很紧密的对象
  • 每个聚合都有一个根,有一个边界
  • 聚合根控制了对这个聚合内所有对象的访问,外部要想访问内部对象,必须通过聚合根才行
  • 聚合举例
  • 用户直接调用
    car.ride()
  • 用户直接操作细节
if(car.getTires).getUsageLevel() < Car.ACCEPTABLE_TIRE_USAGE){
    for(Wheel w: car.getWheels(){
        w.spin();
    })
}
  • 聚合的特点
  • 根实体有全局标识(例如 OrderId)
  • 聚合内的实体有本地标识(只在聚合内部是唯一的,例如LinItem的序号)
  • 聚合外部的对象不能直接引用除了根之外的对象
  • 可以把一个值对象的copy传递给外界,该副本和聚合没有关联
  • 只有聚合的根才能通过数据库被装载
  • 删除操作会把聚合内的所有对象删除
  • 当对聚合边界内任何对象做修改时,聚合内的规则必须被满足(例如Order的总价格和各个LineItem的价格和要相等)

重建已经存储的领域对象:资源库

  • 工厂负责创建对象
  • 资源库(Repository)从存储中重建对象
  • 不分配唯一的标识,标识是输入参数的一部分
  • 资源库“说”的是领域语言

总结

DDD是一套原则和模式,主要聚焦设计

  • 理解领域(软件需要在领域内工作)
  • 建立这个领域富有表达力的模型
  • 提取通用语言

DDD构造块

  • 分层架构
  • 实体、值对象、领域服务
  • 聚合
  • 工厂、资源库

DDD获取成功的条件

  • 你面对的不是一个简单的领域
  • 否则直接用贫血模型就OK了
  • 你可以和领域专家合作
  • 你有一个迭代式的开发过程
  • 你有一个技能熟练的、能够自我激励的团队
  • 一定要把这个系统做好!