知识卡片

DDD与面向对象的关系:建模范式须与编程范式一致

结构图卡

内容

DDD要求设计模型与代码实现保持一致——模型能直接指导代码实现,代码的改变也会反过来影响模型;而模型是由”建模范式”决定的,代码是由”编程范式”决定的,如果希望DDD的设计模型能直接指导代码实现,建模范式就必须与编程范式保持一致(代码用面向过程实现,模型构建也该用面向过程方式)。三种主流编程范式的演进:面向过程(20世纪60年代第一次软件危机中诞生,基本单元是过程函数)→面向对象(面向过程无法解决可组合性/可扩展性问题、引发第二次软件危机后诞生,基本单元是类)→函数式编程(理论提出较早,直到多核CPU和分布式计算兴起才受关注,基本单元是函数);DDD虽声称适用于各种编程语言,但因面向对象普及,大部分DDD材料介绍的领域模型都采用面向对象方式。DDD与面向对象真正的关系要从面向对象的局限说起:面向对象分析常用用例图梳理系统功能,对简单系统很有用,但系统变复杂、涉及不同领域时,用例模型可能出现概念不一致的问题(比如银行存款用例图和贷款用例图都有”检查协议”,名字相同但内涵不同)——这说明面向对象更适合解决”某一领域内没有概念歧义性”的系统,而这恰恰正是DDD战术设计阶段擅长的地方:战术设计阶段已经明确定义了限界上下文(即微服务的边界),限界上下文内用一致的描述语言消除了歧义,所以战术设计阶段天然适合面向对象技术。DDD与面向对象真正的不同之处在于战略设计阶段——它要解决的正是面向对象跨领域建模时可能面临的歧义问题:如果概念存在歧义,就把它们划分到不同的领域(哪怕系统很复杂、所有概念都没有交集,比如电商里物流和购物看似无关,也可以用DDD拆分开、让不同团队分工解决)。总之,DDD战术设计阶段和面向对象密切相关,而战略设计阶段的主要目标是进行领域和子领域拆分,让拆分后的每个限界上下文能更好地应用面向对象技术来实现。

结构图

flowchart TB
  M["建模范式必须与编程范式一致"]
  M --> P["面向对象普及<br/>→DDD领域模型多采用面向对象方式"]
  Q["面向对象的局限:跨领域概念歧义<br/>(如存款/贷款用例图里含义不同的'协议')"]
  Q --> T["DDD战略设计:划分领域/子领域<br/>解决跨领域歧义问题"]
  T --> C["限界上下文内:一致语言,无歧义"]
  C --> O["DDD战术设计:适合用面向对象技术实现"]

参考来源

- 位置:《架构师启示录:知识模型、落地方法与思维模式》第7章《架构设计》之"7.4.1 DDD与面向对象的关系"(源文件:_epub-src/EPUB/xhtml/chapter11.xhtml) - 结论依据:原文说明"如果希望DDD中的设计模型能直接指导代码实现,那么建模范式需要与编程范式保持一致……至少可以肯定面向对象更适合直接解决那些某一领域内没有概念歧义性的系统……在DDD战术设计阶段,已经明确定义了限界上下文……并且在限界上下文内使用一致的描述语言消除了歧义……DDD与面向对象真正的不同之处在于DDD的战略设计阶段,而要解决的问题正好是面向对象在跨领域建模时可能面临的歧义问题", 直接支撑本卡关于DDD与面向对象关系的结构图。 - 原始内容:在存款用例图中,包括检查协议和账户等功能;而在贷款用例图中,同样包括检查协议和账户功能。尽管这里都称之为"协议",但其内涵是不同的。