DDD领域设计模型

这里写自定义目录标题


一、 背景
最近公司组织架构调整,项目组的重心将会放在金融账户和支付,需要新搭建项目,原项目架构结构比较传统,笨重且难维护的弊端明显,最终选型最佳较火的DDD领域设计模型,经学习与总结如下:

二、什么是 DDD 领域驱动设计
领域驱动设计(Domain-Driven Design,DDD)是一种软件设计方法,它重点关注软件开发中涉及的领域概念,旨在帮助团队在复杂系统中实现业务逻辑。
DDD 的核心思想是将实现连接到持续进化的模型,通过领域模型驱动系统设计。它倡导统一语言,提出了一系列概念,包括实体、值对象、聚合根等,以帮助团队更好地理解和表达业务模型。
领域驱动设计的目标是通过清晰的领域模型、领域语言和领域边界来理解和解决业务问题。它鼓励跨职能团队的合作,以确保软件系统与业务需求保持一致,并且能够应对变化和复杂性。通过领域驱动设计,开发团队可以更好地与业务领域专家进行沟通,减少误解,提高软件的质量和可维护性。
DDD 打破了传统软件开发中需求分析和系统设计之间的隔阂,使得软件能够更灵活、快速地跟随需求变化。它在国外已成为主流,是解决复杂大型软件问题的一套行之有效的方法。

三、DDD 的四层领域模型
DDD的四层领域模型如下所示:

  1. 展现层:这一层负责向用户显示信息和解释用户命令,完成前端界面逻辑。并将用户请求传递给应用层。
  2. 应用层:这一层是很薄的一层,负责协调领域层中的领域对象,组成具体应用场景。应用层要尽量简单,不包含业务规则或者知识,不保留业务对象的状态,只保留有应用任务的进度状态,更注重流程性的东西。应用层直接依赖于领域层,由领域层提供具体的业务能力。
  3. 领域层:这是业务软件的核心所在,包含了业务所涉及的领域对象(实体、值对象)、领域服务以及它们之间的关系,负责表达业务概念、业务状态信息以及业务规则,具体表现形式就是领域模型。DDD 强调领域层不需要任何外部依赖,只是反应软件核心的业务能力。
  4. 基础设施层:这一层向其他层提供通用的技术能力,为应用层传递消息(API 网关等),为领域层提供持久化机制(如数据库资源)等。
    在四层领域模型中,展现层与应用层组成了前端应用,领域层与基础设施层组成了后端应用。前后端应用通过API进行通信。
    在DDD中,还有一些基础概念需要了解。其中,聚合根是一个很重要的概念,它代表了一个业务对象群在领域模型中的根节点,可以包含其他多个实体和值对象。聚合根负责管理其包含的对象的状态,以保证其整体的一致性。另外,DDD还提倡使用限界上下文来构建子域,每个限界上下文代表了一个独立的业务能力或主题,可以包含特定的业务逻辑和数据。这些基础概念可以帮助开发人员更好地理解和构建领域模型。

四、贫血模型和充血模型
DDD中的贫血模型和充血模型都是领域模型的表现形式,但是它们在设计和实现上有着显著的区别。
● 贫血模型(Anemic Domain Model)是面向过程编程的一种表现形式。贫血模型的实体只包含数据属性和对应的 getter 以及 setter,而具体的业务逻辑交由服务层或其他外部组件负责。贫血模型将数据与操作分离,其好处是模型足够简单,开发上手比较快。团队内多人协作时,设计不容易变形。比较适合轻量级应用。但坏处是贫血模型的实体无法直接体现对应的业务能力,在复杂业务中,梳理业务逻辑将变得非常困难,不利于项目后期的业务演进。
● 充血模型(Rich Domain Model)则是面向对象编程的一种表现形式。充血模型的实体通常包含了数据属性以及引起属性发生变化的核心业务动作。充血模型将数据与业务能力绑定在一起,非常符合业务人员的思考方式,因此其好处是对业务非常友好,有助于更好的封装和保护领域内部的业务规则,尤其适合业务复杂的应用场景。充血模型的坏处是对业务的熟悉程度要求很高,需要在上手之初就设计好针对不同的业务场景,设计好具体的模型实体,并且规划好需要暴露哪些操作,定义哪些业务逻辑。而这些在贫血模型中则不需要,可以边实现边修改。
总的来说,贫血模型更注重简单性和易上手,而充血模型更注重业务复杂的系统开发。选择使用哪种模型取决于具体的业务需求和开发团队的技术能力。

五、如何处理模型的聚合和聚合根
在DDD中,聚合是指一组紧密关联的实体和值对象,它们共同完成一个特定的业务逻辑,并由一个聚合根进行管理。聚合根是聚合的根节点,它作为聚合内堆外暴露的唯一访问入口,负责管理聚合内部的对象状态,并协调它们之间的交互。
处理模型的聚合和聚合根主要涉及以下步骤:

  1. 识别聚合:在领域模型中,识别出具有紧密关联的实体和值对象,它们共同构成了一个聚合。这些实体和值对象应该符合高内聚、低耦合的设计原则,具有一致的业务语义和行为。
  2. 定义聚合根:在确定了聚合之后,需要选择一个合适的对象作为聚合根。聚合根应该是一个具有全局唯一性的对象,例如一个订单聚合,包含订单、商品、地址、用户等多个实体,而这其中订单就是一个很好的聚合根。
  3. 保证聚合内部的一致性:确保聚合内部的对象之间保持一致性,即要么一起成功创建、修改、删除,要么一起失败。聚合根负责协调聚合内部的操作。
  4. 限制聚合外部访问:聚合形成之后,外部对象只能通过聚合根来访问聚合内的对象。聚合跟负责限制对聚合内部对象的直接访问,以维护聚合的完整性。例如形成订单聚合后,对订单聚合内部的商品、用户进行访问,都必须通过订单实体进行。
  5. 合理规划业务行为:DDD的设计过程中,更强调对实体状态的变化梳理。因此,一些不会引起实体状态变化的操作,例如查询,就不必要严格按照聚合进行划分。例如,想要一天内卖出了哪些商品,这个操作并不会引起实体状态发生变化,因此就不需要严格按照聚合的要求,先访问订单这个聚合根,再统计订单中的商品。而可以跨过订单,直接统计卖出的商品。
  6. 暴露聚合的服务:在聚合根中暴露一些服务,以便其他应用程序可以访问聚合内部的数据和业务逻辑。这些服务可以是领域服务或者应用服务,它们应该遵循统一的接口规范,并且应该保证安全性。
    总之,在DDD中,处理模型的聚合和聚合根需要仔细考虑聚合的设计和实现,包括聚合的组成、聚合根的选择、聚合内部的关系、聚合的行为以及聚合服务的暴露等方面。通过合理的设计和实现,可以提高系统的可维护性、可扩展性和可重用性。

六、实体和值对象
在DDD中,实体 Entity 和值对象 Value Object 是两个基本的概念,它们之间有一些重要的区别。

  1. 唯一性:实体是唯一的,每个实体都有一个唯一的标识符,即使它的属性在一段时间内发生了变化,它仍然是这个实体。与之不同,值对象可以有一组属性,这些属性可以描述一个事物的状态或特征,但它们没有唯一的标识符,即使两个值对象的属性完全相同,它们也被视为两个不同的对象。
  2. 状态变化:实体可以有状态,并且可以在不同的时间或场景下有不同的状态。例如,一个订单实体可能在创建时是一个待支付状态,支付后变为已支付状态,而值对象通常只有固定的属性,不会有状态变化。
  3. 生命周期:实体有一个明确的生命周期,它可能随着时间的推移而创建、更新或删除,而值对象没有自己的生命周期,它们通常是在需要时创建,并在不再需要时被垃圾回收。
  4. 相等性:对于实体来说,两个具有相同标识符的实体是相同的,无论它们的状态如何。对于值对象,两个具有相同属性的值对象被认为是相等的,但这需要通过比较它们的属性来确定。
    综上所述,实体和值对象在DDD中是两种不同的概念。在 DDD 中,实体通常用于表示有唯一表示以及状态变化的领域概念,而值对象通常用于表示无唯一标识以及不可变的属性集合。值对象形式上是一个对象,但是其本质则和一个属性值是等价的。

七、领域对象
在 DDD 中,领域对象的持久化工作通常是通过仓库 Repository 和工厂 Factory 实现的。仓库是一种用于访问领域对象的机制。他负责将领域对象从内存中保存到持久存储,如数据库,中,以及从持久存储中检索领域对象。而工厂则负责从持久存储中组装领域对象。
在处理领域对象的持久化时,通常需要注意以下几个问题:
● 定义仓库接口:为每个需要持久化的领域对象创建一个对应的仓库接口。这个接口通常包含了一组方法,用于对领域对象进行存储和检索操作。而在实现仓库接口时,通常可以使用泛型,扩大接口的适用场景。
● 通过工厂组装实体:DDD中的实体包含很多面向对象的业务特色,而数据库中的数据往往带有很多技术特色。这时,通过工厂的设计,可以让实体设计摆脱具体数据库的限制,从而让实体能够真正面向业务进行构建而不用考虑具体数据库技术的影响。

  1. 合理进行业务隔离:在DDD中,数据的访问和修改应该通过仓库和工厂来完成,而不是直接访问数据库。仓库和工厂应该提供统一的接口来访问和修改数据,这样可以保证数据的完整性和一致性。
    ● 事务管理:在处理领域对象的持久化时,通常需要考虑事务管理。确保在保存或检索领域对象时,事务能够正确地提交或回滚,以保持数据一致性。
    ● 隔离异常:与数据库的交互过程中产生的异常,应该在仓库和工厂中进行封装。这些业务异常尽量不要蔓延到领域层。
    总之,在DDD中,仓库和工厂是两个核心的概念,它们的设计应该考虑到应用的需求、领域模型的结构、数据的访问和修改等方面。通过合理的设计,可以提高系统的可维护性、可扩展性和可重用性。

八、CQRS 模式
领域驱动设计(DDD)中的CQRS模式是一种架构模式,它将系统中的操作分为两类:命令(Command)与查询(Query)。CQRS 模式强调了应用程序要将命令和查询愤慨处理。
● 命令是对会引起数据发生变化的操作的总称,如新增、更新、删除等操作。命令通常是不返回数据的,它们只用于触发状态变化。
● 查询则是对不会对数据产生变化的操作的总称,例如按照某些条件查找数据。它们用于获取系统状态的快照或特定信息。查询通常返回数据给客户端
在CQRS模式中,命令和查询应在两个独立的系统中处理,这两个系统一般是指两个独立部署的应用程序,在某些特殊情况下,也可以部署在同一个应用内的不同接口上。通过分离职责、使用不同的数据存储和事件驱动的方式,允许更好地满足系统的性能和可伸缩性需求。
在使用CQRS模式时,通常也需要面临一些问题,例如事务和查询模型的设计。在事务方面,由于命令和查询分别在不同的系统中处理,因此需要解决时间差问题以及更新操作失败可能导致的数据不一致性问题。在查询模型设计方面,需要解决查询接口过多的问题,可以将属于同一领域的查询集中管理作为整个查询系统的一个上下文,或者将它们独立出来作为一个微服务。
总之,在DDD中,CQRS模式可以将领域模型与查询功能进行分离,使一些复杂的查询摆脱领域模型的限制,以更为简单的DTO形式展现查询结果。同时也可以分离不同的数据存储结构,使开发者更加自由地选择数据存储引擎。虽然引入CQRS模式会引入额外的复杂性和技能要求,但在面对大型业务系统和复杂的业务流程时,使用CQRS模式可以帮助将命令和查询进行拆分,使领域模型与数据模型的边界更加清晰。

九、跨多个实体的复杂业务
在DDD中,跨多个实体的复杂业务通常需要交由领域服务进行协调。领域服务的设计应该遵循以下原则:

  1. 定义服务接口。领域服务应该定义一个清晰的接口,这个接口应该包含需要实现的方法和参数。这样可以使得其他模块能够使用这个服务而不需要关心具体的实现细节。
  2. 实现业务逻辑。领域服务的实现应该包含具体的业务逻辑,这是领域服务的核心。业务逻辑应该根据业务需求进行设计和实现,可以跨越多个聚合或领域。
  3. 暴露业务数据。领域服务可以暴露一些业务数据给其他模块使用,但是需要注意数据的封装和安全性。对于敏感数据,应该遵循最小权限原则,限制其他模块的访问权限。
  4. 尽量减少依赖。领域服务应该尽量减少对其他模块的依赖,这样可以使得领域服务更加独立和可维护。
  5. 考虑可测试性。领域服务的实现应该考虑可测试性,使得我们可以方便地对领域服务进行单元测试和集成测试。
  6. 定义服务调用方式。领域服务可以定义为本地服务或远程服务,根据业务需求和系统架构进行选择。对于远程服务,需要考虑网络通信、服务调用的性能和安全性等方面的问题。
    处理跨多个实体的复杂业务是DDD中的一个关键挑战,需要深入理解业务领域、合理划分聚合、制定适当的领域服务和规则,以及不断进行建模和迭代来满足实际需求。领域驱动设计的方法和模式可以帮助团队更好地理解和应对这种复杂性。

十、限界上下文
在DDD中,"限界上下文"是一个非常重要的概念,它指的是一个边界内的领域模型和与之相关的语义环境。限界上下文(Bounded Context)是一种用于定义和隔离领域模型的概念。每个限界上下文都代表了一个明确定义的、有边界的领域模型,用于描述业务领域的一部分。限界上下文有助于在大型系统中管理和组织复杂的领域模型,并确保不同部分之间的一致性和清晰性。
限界上下文可以看作是一种语义上的边界,它可以将领域模型与外部环境隔离开来,保证领域模型的独立性和纯净性。在这个边界内,领域模型的概念和操作都有着明确的含义,不会受到外部因素的干扰和影响。
通过限界上下文,团队成员可以更加清晰地了解业务领域,并在这个边界内进行交流和协作。限界上下文可以帮助团队成员避免使用不准确或歧义性的术语,使交流更加准确、高效。
另外,限界上下文还可以作为微服务设计的重要参考。在微服务设计中,不同服务之间的边界是很重要的,而限界上下文可以帮助我们更好地理解和规划这些服务的边界。在很多情况下,限界上下文的边界往往就是微服务的边界,这可以帮助我们更好地拆分和设计微服务。
总之,限界上下文是DDD中的关键概念之一,它可以帮助我们更好地描述和理解业务领域,提高团队成员的协作效率,同时也可以作为微服务设计的重要参考。

十一、如何在微服务架构中使用领域驱动设计
在微服务架构中使用领域驱动设计(DDD)可以帮助我们更好地理解和设计业务领域,以下是在微服务架构中使用DDD的一些简洁的步骤:

  1. 定义微服务边界,每个微服务对应一个限界上下文,有自己的领域模型和语言。
  2. 使用领域模型来建模每个微服务的核心业务逻辑,包括实体、值对象、聚合、领域服务等。并定义它们之间的关系和交互。
  3. 明确微服务之间的接口和通信协议,如HTTP/REST或AMQP等。基于领域模型定义接口。
  4. 使用事件驱动架构来确保微服务之间的数据同步。
  5. 每个微服务拥有自己的仓库与工厂,负责数据的管理和持久化。
  6. 团队结构应该反映微服务的划分,每个团队专注于自己的微服务。
  7. 自动化部署和运维,使用监控工具来跟踪微服务性能。
  8. 不断迭代和改进微服务,根据反馈优化系统。
    总之,在微服务架构中使用领域驱动设计可以提高系统的可维护性和可扩展性,通过定义领域模型、识别限界上下文、设计聚合根和聚合、实现领域服务、实现微服务接口、使用通信协议进行微服务交互以及实现数据存储等步骤来构建出高质量的微服务架构。
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
领域模型是软件开发中用于描述业务领域的概念和关系的一种建模方式。它主要用于帮助开发人员理解业务需求,并将其转化为可执行的软件系统。 在领域模型设计中,DDD(Domain-Driven Design,领域驱动设计)是一种常用的方法论。DDD强调将业务领域作为软件开发的核心,通过深入理解业务需求,将业务逻辑和领域模型进行有效的建模和设计。 在DDD中,领域模型是对业务领域中的实体、值对象、聚合根、领域服务等概念进行建模和描述的一种方式。它通过定义实体之间的关系、属性和行为,以及业务规则和约束,来描述业务领域的核心概念和逻辑。 领域模型设计的过程通常包括以下几个步骤: 1. 领域分析:深入理解业务需求,识别出业务领域中的核心概念和关系。 2. 实体建模:将业务领域中的实体抽象成具有属性和行为的对象,并定义它们之间的关系。 3. 聚合根设计:将相关联的实体组织成聚合根,通过聚合根来管理和维护实体之间的一致性和完整性。 4. 值对象定义:将不可变的、没有唯一标识的对象抽象成值对象,用于描述业务领域中的属性和属性集合。 5. 领域服务划分:将业务领域中的复杂业务逻辑抽象成领域服务,通过服务来实现业务操作和交互。 6. 领域事件设计:定义领域中的事件,用于表示业务领域中的状态变化和重要的业务行为。 通过合理的领域模型设计,可以提高软件系统的可维护性、可扩展性和可理解性,使开发人员更加专注于业务逻辑的实现。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值