DDD架构的理解与应用

软件开发中的挑战和问题

复杂性管理

当处理复杂业务需求时,软件系统往往变得复杂,难以理解和维护。不清晰的业务逻辑和模型使开发人员难以捕捉并准确地实现业务需求。

领域专家与开发人员之间的沟通障碍

业务专家负责提供业务需求和知识,而开发人员负责将这些需求转化为可执行的软件系统。然而,由于不同的专业背景和术语之间的差异,很难进行有效的沟通,造成开发过程中的误解和偏差。

数据库驱动设计的局限性

在传统的软件开发中,往往将数据库设计作为业务逻辑的中心。这导致了紧密耦合的数据模型和业务逻辑,使系统变得脆弱且难以修改和扩展。

难以应对变化

在现实世界中,业务需求会不断变化和演化。然而,传统的软件开发方法往往缺乏灵活性,难以适应这种变化。系统修改和扩展常常会引入错误和破坏现有的结构。

DDD 架构的定义和目标

当谈到领域驱动设计(Domain-Driven Design,DDD)架构时,它是一种软件设计方法,旨在帮助开发人员更好地理解和解决复杂业务领域的挑战。DDD 架构的目标是将软件设计与实际业务需求紧密结合,通过明确的领域模型和业务概念来支持系统的开发和演化。

定义

领域驱动设计是一种基于领域模型的软件设计和开发方法,强调将软件设计与业务领域的实际需求相结合。它提供了一组原则、模式和工具,帮助团队更好地理解业务领域、捕捉业务知识,并以清晰的方式将其映射到软件系统中。

目标

  • 解决复杂性:DDD 通过将业务领域划分为明确的模块和概念,帮助开发人员处理复杂性。它鼓励建立一个明确的、可靠的领域模型,帮助开发人员更好地理解和应对业务领域的挑战,从而简化开发过程。
  • 清晰的业务模型:DDD 强调提取和表达业务知识,并将其映射到软件系统中的领域模型。通过建立一个明确的、统一的领域模型,团队成员可以共享对业务概念和规则的理解,促进更好的沟通和对业务需求的一致性理解。
  • 高度可维护性:DDD 倡导使用清晰的领域模型来构建软件系统,这有助于提高系统的可维护性。通过将业务逻辑和状态封装在领域对象中,并使用聚合根等DDD模式,可以简化代码结构,降低耦合性,从而使系统更易于修改和扩展。
  • 迭代开发和增量交付:DDD 鼓励采用增量开发和敏捷方法,通过迭代方式逐步完善和验证领域模型。它强调与领域专家密切合作,通过快速迭代的方式逐步演化系统,以满足不断变化的业务需求。
  • 技术和业务的融合:DDD 鼓励技术人员和业务专家之间的紧密合作,通过共同理解和共享语言来构建一个有效的领域模型。它试图消除技术术语和业务术语之间的隔阂,促进团队之间的有效沟通和协作。

💡以领域作为切入点,提炼领域概念,分析概念之间的关系,构建领域模型解决业务问题。

通过遵循 DDD 架构的原则和模式,开发人员可以更好地理解和解决复杂业务需求,构建可维护、高度设计的软件系统,并与业务专家进行更紧密的合作。这种方法有助于确保软件系统与实际业务需求的一致性,提高开发效率并最大程度地满足用户需求。

DDD 架构的重要性

💡 DDD(领域驱动设计)架构的重要性在于它提供了一种将软件系统的复杂业务逻辑与技术实现相结合的方法。它强调以领域模型为核心,通过深入理解和准确映射业务领域,来解决传统开发中的一些常见问题,提高软件系统的可维护性、可扩展性和灵活性。

业务复杂性管理

软件系统往往涉及复杂的业务需求和逻辑。DDD 提供了一种将复杂业务逻辑进行建模和组织的方法,通过领域模型的概念和规则,使开发人员能够更好地理解和处理复杂性,降低系统的认知负担。

高效的沟通和协作

DDD 强调业务专家与开发人员之间的紧密合作。通过共同创建和维护领域模型,业务专家能够更有效地表达需求和规则,开发人员可以更准确地理解和实现这些需求。这种良好的沟通和协作有助于减少开发过程中的误解和偏差,提高开发效率和质量。

高内聚、低耦合的模块化设计

DDD 通过将软件系统划分为多个领域模型和限界上下文,强调模块化和边界的概念。每个模块都有自己的职责和规则,模块之间通过清晰的接口进行交互,从而实现高内聚、低耦合的设计。这种模块化的设计使系统更易于理解、修改和扩展,提高了系统的可维护性和灵活性。

支持变化和演化

DDD 提倡对业务需求的变化持开放态度,并提供了适应变化的方法。通过领域模型的概念,DDD 强调将业务逻辑和规则封装在模型中,使其更易于修改和演化。当业务需求发生变化时,可以通过调整模型而不是整个系统来适应变化,减少对系统的影响。

提高软件质量

DDD 强调关注业务领域本身而非技术细节,帮助开发人员更好地理解业务需求。通过准确映射业务领域,可以更容易地验证系统的正确性和完整性。同时,DDD 还鼓励使用领域驱动测试来验证领域模型的行为,确保系统按照预期工作。

DDD架构的价值

  • 边界清晰的设计方法:通过领域划分,识别哪些需求应该在哪些领域,不断拉齐团队对需求的认知,分而治之,控制规模。
  • 统一语言:团队在有边界的上下文中有意识地形成对事物进行统一的描述,形成统一的概念(模型)。
  • 业务领域的知识沉淀:通过反复论证和提炼模型,使得模型必须与业务的真实世界保持一致。促使知识(模型)可以很好地传递和维护。
  • 面向业务建模:领域模型与数据模型分离,业务复杂度和技术复杂度分离。

DDD架构适用场景

复杂业务系统

当开发的软件系统涉及复杂的业务需求和逻辑时,DDD 可以帮助将这些复杂性进行合理组织和管理。

长期维护和演化

当软件系统需要长期维护和演化时,DDD 的模块化设计和适应变化的特性能够降低修改和扩展的风险。

多团队协作

当多个团队同时开发一个大型软件系统时,DDD 提供了明确的边界和接口定义,有助于不同团队之间的协作和集成。

高度可定制的业务需求

当业务需求需要高度定制化和个性化时,DDD 的领域模型可以准确表达特定的业务规则和行为。

DDD架构的核心概念

领域模型和领域对象的概念

💡领域模型和领域对象是领域驱动设计(DDD)中的两个核心概念,它们在软件开发中起着重要的作用。

领域模型(Domain Model)

领域模型是对业务领域的抽象和建模,它描述了业务中的概念、规则和关系。领域模型是对现实世界的业务问题进行抽象的结果,它反映了业务专家对领域的理解,并将其表达为软件系统中的对象和逻辑。领域模型通常由实体(Entities)、值对象(Value Objects)、聚合(Aggregates)、服务(Services)等组成。

领域模型的设计旨在准确地反映业务领域的本质特征,并将其与技术实现相分离。通过领域模型,开发人员能够更好地理解业务需求、规则和流程,提供一种共享的语言,促进开发团队与业务专家之间的沟通与协作。

特点
  1. 领域模型是对具有某个边界的领域的一个抽象,反映了领域内用户业务需求的本质;领域模型是有边界的,只反应了我们在领域内所关注的部分;
  2. 领域模型只反映业务,和任何技术实现无关;领域模型不仅能反映领域中的一些实体概念,如货物,书本,应聘记录,地址,等;还能反映领域中的一些过程概念,如资金转账,等;
  3. 领域模型确保了我们的软件的业务逻辑都在一个模型中,都在一个地方;这样对提高软件的可维护性,业务可理解性以及可重用性方面都有很好的帮助;
  4. 领域模型能够帮助开发人员相对平滑地将领域知识转化为软件构造;
  5. 领域模型贯穿软件分析、设计,以及开发的整个过程;领域专家、设计人员、开发人员通过领域模型进行交流,彼此共享知识与信息;因为大家面向的都是同一个模型,所以可以防止需求走样,可以让软件设计开发人员做出来的软件真正满足需求;
  6. 要建立正确的领域模型并不简单,需要领域专家、设计、开发人员积极沟通共同努力,然后才能使大家对领域的认识不断深入,从而不断细化和完善领域模型;
  7. 为了让领域模型看的见,需要用一些方法来表示它;图是表达领域模型最常用的方式,但不是唯一的表达方式,代码或文字描述也能表达领域模型;
  8. 领域模型是整个软件的核心,是软件中最有价值和最具竞争力的部分;设计足够精良且符合业务需求的领域模型能够更快速的响应需求变化;
领域对象(Domain Object)

领域对象是领域模型中的具体实体,代表了业务领域中的一个概念或实体。它是领域模型中的核心元素,包含了数据和行为,并且具有业务规则和约束。领域对象通常具有唯一的标识,并通过标识来进行区分和操作。

领域对象不仅包含了数据的状态,还具有对这些数据进行操作和处理的方法。它封装了业务行为和逻辑,实现了业务规则的验证和执行。领域对象的设计应该注重领域的本质特征,准确表达业务需求,并通过方法的行为来保护和维护其内部数据的完整性和一致性。

领域对象在领域模型中相互交互和协作,通过消息传递和调用方法来实现业务流程和功能。它们可以形成聚合,建立关联关系,参与业务规则的执行和数据的变更。

子域

可以理解为更加细分的领域,甚至可以将子域进行更加的细分,分成更多的子域。

核心子域

是整个业务领域的一部分,是整个业务系统的核心,所有的鄂业务都要围绕核心业务展开,也是业务功能的主要促成因素,它是业务成功的主要因素和公司的核心竞争力。直接对业务产生价值

就是不包含核心竞争力的功能,也不包含通用功能,撑其他领域业务,具有企业特性,不具有通用性。直接对业务产生价值

通用子域

没有太多个性化的功能设计,同时被多个子域使用的通用功能子域。间接对业务产生价值

限界上下文

主要是语言层面上的限界划分,用来封装通用语言和领域对象,提供上下文环境,保证在领域内的一些术语、业务相关对象等有一个确切的含义,没有二义性。是实现DDD的关键。一个限界上下文并不一定只包含在一个子域中。限的意思就是划分、规定,界就是界限、或者一个边界,上下文就是业务的整个流程。限界上下文定义了领域模型的边界,目的是清理子域,然后区分子域哪些是核心域、支撑子域和通用子域。

服务(Service)

服务是领域模型中的一种行为抽象,它表示一组操作或行为的集合,通常与领域对象无关。服务可以是无状态的,也可以是有状态的,它们通过接口或者静态方法来提供服务。

特点
  • 封装行为:服务封装了一组操作或者行为,在方法级别上对领域操作进行了组织和归纳。
  • 强调整合:服务跨越多个领域对象,协调它们之间的交互,促进领域模型的整体性和一致性。
  • 面向操作:服务的主要目的是执行某个操作,并且不保留任何状态。
作用
  • 处理复杂的领域操作,协调多个实体或值对象之间的交互。
  • 提供领域无关的功能,例如验证、计算等。
  • 支持领域模型的完整性和一致性。

DDD 架构的分层思想

分层架构的概述和优势

💡领域驱动设计(Domain-Driven Design,DDD)分层架构是一种常用于构建复杂软件系统的架构风格。它将系统划分为多个层次,每个层次都有特定的职责和关注点,以实现高内聚低耦合的目标。
 

概述

DDD分层架构基于单一职责原则(Single Responsibility Principle)和依赖倒置原则(Dependency Inversion Principle)构建,提供了一种将业务逻辑、领域模型和基础架构等不同关注点进行分离的方式。

DDD分层架构的组成

用户界面层(User Interface Layer):负责与用户交互,展现系统的用户界面,接收用户输入和显示输出,调用应用层完成具体用户请求。包含:controller,远程调用服务等。

应用层(Application Layer):尽量简单,不包含业务规则,只为了下一层中的领域对象做协调任务,分配工作,重点对领域层做编排完成复杂业务场景。包含:AppService,消息处理等。协调用户界面和领域层之间的交互,处理用户请求,调用领域服务和领域对象来完成业务逻辑。

领域层(Domain Layer):包含领域模型、实体、值对象、域服务、事件等,负责表达业务概念和业务逻辑,实现业务规则和行为,封装核心的业务逻辑,领域层是系统的核心。

基础架构层(Infrastructure Layer):提供与基础设施相关的支持,包括数据操作、发送消息、消费消息、缓存、日志等。

调用关系:用户接口层->应用层->领域层->基础层

依赖关系:用户接口层->应用层->领域层->基础层

六边形架构

系统通过适配器的方式与外部交互,将应用服务于领域服务封装在系统内部,依然是分层架构,它核心改变的是依赖关系。

领域层依赖基础层倒置成基础层依赖领域层,这个变化使领域层不依赖任务层,其他层都依赖领域层,使领域层只表达业务逻辑且稳定。

调用链路

优势

高内聚低耦合:通过将不同关注点分离到不同层中,实现了高内聚和低耦合。每个层次都有明确的职责,可以更容易理解和维护。

可测试性:每个层次可以独立测试,因为它们的职责清晰,依赖关系明确。这样可以更容易编写单元测试和集成测试,提高代码质量。

可扩展性:由于各层之间的松散耦合,当需要添加新功能或修改现有功能时,只需修改特定的层次,而无需影响其他层次。

可维护性:DDD分层架构使得系统的各个部分有明确的职责和边界,降低了代码的复杂性,提高了代码的可读性和可维护性。

模块化开发:不同层次之间的分离使得开发团队可以更好地并行工作,各自专注于自己的任务,提高开发效率。

要注意的是,DDD分层架构并不是一成不变的,具体的架构设计可能因系统规模、团队结构和业务需求等因素而有所调整。重要的是理解各层次的职责和关注点,并保持良好的代码组织和架构设计原则,以实现可维护、可扩展的软件系统。

领域层、应用层和基础设施层的职责和关系

领域层
职责

领域层是整个系统的核心,负责实现业务规则和逻辑。它包含了领域模型、实体、值对象、聚合根等概念

主要完成以下职责:

  • 实现业务领域的概念和规则。
  • 封装核心的业务逻辑。
  • 管理领域对象之间的关系和交互。
  • 保证数据的一致性和有效性
关系

领域层通常不依赖于其他层,并且其他层也不应该直接依赖于领域层。它通过定义接口或领域服务的方式暴露给应用层,应用层可以调用领域层的接口或服务来处理业务逻辑。

应用层
职责

应用层作为领域层和用户界面层之间的协调者,负责处理用户请求、协调领域对象和领域服务来完成业务逻辑。

主要完成以下职责:

  • 接收和验证用户输入。
  • 转化用户请求为领域对象的操作。
  • 协调多个领域对象之间的交互和协作。
  • 调用领域服务来完成复杂的业务操作。
关系

应用层依赖于领域层,通过调用领域层中的接口或领域服务来实现业务逻辑。它还可以调用基础设施层提供的服务来处理与外部系统的交互。

基础设施层
职责

基础设施层提供与基础设施相关的支持,包括数据库访问、消息队列、外部API调用、缓存、日志等功能。主要完成以下职责:

  • 与外部系统进行通信和交互。
  • 提供数据持久化的支持,例如数据库访问、ORM等。
  • 实现与基础设施相关的技术细节,例如日志记录、缓存管理等
关系

基础设施层依赖于应用层和领域层,它为这些层提供必要的支持和服务。例如,领域层和应用层可以通过基础设施层访问数据库、记录日志或发送消息。

✨总体而言,领域层关注业务逻辑和规则应用层协调业务逻辑的执行基础设施层提供系统级的技术支持。它们之间的关系是领域层不依赖其他层应用层依赖领域层基础设施层提供支持给应用层和领域层

领域事件

定义

领域事件是指在领域模型中发生的具有业务意义的、可追溯的事情或状态变化。它通常表示系统中重要的业务行为或关键的业务状态转换。

使用场景

使用领域事件可以捕捉和记录领域模型中的重要业务行为,以便在该事件发生后执行相应的业务逻辑

常见使用场景
  • 触发其他领域对象的行为或状态变化。
  • 提供领域对象之间的解耦,使得系统更加灵活和可扩展。
  • 记录和跟踪系统的状态变化,以满足审计需求。
  • 与外部系统进行异步通信,例如发布消息给消息队列。
实现方式

领域事件通常由领域对象产生并发布,可以使用观察者模式或发布-订阅模式进行订阅和处理。在事件发布时,应用层或基础设施层可以监听并执行相应的业务逻辑

领域服务

定义

领域服务是指在领域模型中提供的一种操作或功能,它不属于任何特定的领域对象,而是用于协调多个领域对象之间的交互和实现复杂的业务逻辑。

使用场景

使用领域服务可以处理那些涉及多个领域对象或需要跨领域边界的业务操作。

常见使用场景
  • 处理涉及多个领域对象的复杂业务逻辑。
  • 跨聚合根或子域执行事务性操作。
  • 与外部系统进行交互或集成。
实现方式

领域服务通常被定义为领域模型中的一个接口或抽象类,并由具体的实现类来提供具体的操作。在应用层中,可以通过调用领域服务的方法来执行相应的业务逻辑。

DDD 架构的设计原则和模式

设计原则

聚合根
  • 聚合根(Aggregate Root)是领域模型的核心,它是一组具有内聚性的相关对象的根实体。聚合根负责维护整个聚合内的一致性和业务规则。
  • 通过定义聚合根,可以避免直接操作聚合内的对象,而是通过聚合根进行操作,确保聚合的完整性、一致性和封装性。
领域事件驱动
  • 领域事件(Domain Event)是领域模型中重要的业务行为或状态变化的表示。通过使用领域事件,可以实现领域对象之间的解耦和松散耦合。
  • 领域事件的发生可以触发其他领域对象的行为或状态变化,实现业务流程的演进和响应。
领域服务
  • 领域服务(Domain Service)是指不属于任何特定的领域对象,而是用于解决跨多个领域对象的复杂业务逻辑的操作或功能。
  • 领域服务可以协调多个领域对象之间的交互,处理复杂的业务规则和操作,并实现领域模型中无法被单个领域对象所包含的业务。

事务边界和持久化

  • DDD中的聚合通常对应着数据库事务的边界,一个聚合就是一个单元的数据修改和持久化操作。
  • 聚合根负责控制和维护聚合内对象的一致性,确保整个聚合的状态在事务内是一致的。
  • 聚合根的持久化应该与聚合内部的对象一起进行,保证数据的完整性和一致性。

聚合根和聚合模式的应用可以提高领域建模的粒度和灵活性,将领域对象组织为聚合能够更好地管理对象间的关系和状态变化。使用聚合根和聚合模式能够提高系统的可维护性、可扩展性和并发性,并减少领域模型的复杂度

领域事件和事件驱动模式

领域事件
  • 领域事件是在领域模型中发生的具有业务含义的事情,它记录了一些状态改变或者领域对象之间的交互。
  • 领域事件通过描述事情的发生来反映业务的变化,通常使用过去式的动词来命名,如OrderCreated、ProductStockUpdated等。
  • 领域事件可以被发布和订阅,以便通知其他感兴趣的领域模型或组件进行相应的处理。
事件驱动模式
  • 事件驱动模式是一种软件架构模式,其中系统的行为和状态变化是由触发的事件驱动的。
  • 在DDD中,事件驱动模式用于实现领域模型之间的解耦,通过发布和订阅事件来实现模块之间的通信和协作。
  • 事件驱动模式采用消息传递的方式,领域模型之间通过发布事件和订阅事件来进行通信。
  • 发布者负责发布事件,订阅者通过注册自己的事件处理方法来订阅感兴趣的事件,并在事件发生时执行相应的响应逻辑。
定义领域事件
  • 根据业务需求和领域模型的变化,识别和定义需要引入的领域事件。
  • 给每个领域事件命名,使用过去式的动词来描述事件发生的动作。
实现领域事件
  • 在领域模型中定义并触发相应的领域事件,通常是在领域对象的行为方法中进行触发。
  • 领域事件可以携带一些必要的数据信息,以提供事件处理的上下文和业务参数。
事件发布和订阅机制
  • 实现一个事件发布和订阅的机制,用于将事件传递给感兴趣的订阅者。可以使用消息队列、事件总线等技术来实现。
  • 订阅者通过注册事件处理方法来订阅感兴趣的事件,发布者在事件发生时将事件发送给所有订阅者。
事件处理
  • 订阅者实现相应的事件处理方法,用于接收和处理事件。处理方法根据事件的类型和数据执行相应的业务逻辑。
  • 事件处理方法可以修改自身状态,调用其他领域模型的方法,发送新的命令等。
事件溯源和持久化
  • 可以使用事件溯源机制来记录和存储所有发生的领域事件,以便进行回溯、重放和历史数据分析。
  • 领域事件的持久化可以通过将事件存储到事件日志或数据库中来实现,以保证事件的持久性和可靠性。

✨通过实践领域事件和事件驱动模式,可以实现领域模型之间的解耦、灵活性和可扩展性。事件驱动的方式可以帮助我们构建具有高内聚低耦合的领域模型,并支持系统的可伸缩性和可维护性。在设计和实现过程中,要根据具体业务需求和系统架构选择合适的事件驱动技术和工具。

DDD 架构的应用实践

领域驱动设计的项目实施步骤

  1. 理解业务需求
    在开始实施DDD之前,首先需要充分理解业务需求和上下文。与业务专家合作,深入了解业务领域、业务规则、业务流程等方面的信息。这有助于建立一个准确的领域模型以及对业务的全面理解。
  2. 划定限界上下文

通过定义限界上下文,将业务分成不同的子领域。限界上下文是一种逻辑边界,用于定义和隔离每个子领域的范围。每个限界上下文都与特定的业务功能或业务概念相关联,并有自己的领域模型。

  1. 构建领域模型

针对每个限界上下文,开始构建对应的领域模型。领域模型是对业务领域中的实体、值对象、聚合根、领域服务等各个领域概念的建模。使用领域语言,将业务规则和概念转化为代码实体和对象。

  1. 强调领域模型的设计

领域模型是DDD最核心的部分,需要注重其设计。通过使用领域驱动设计的原则和模式,如聚合、领域事件、领域服务等,来构建可维护、可扩展的领域模型。在设计过程中,可以使用UML类图、领域事件风暴等工具来辅助设计。

  1. 实施战术模式

DDD提供了一系列战术模式用于解决常见的领域建模问题,如实体、值对象、聚合、仓储、领域事件等。根据实际情况选择合适的战术模式来实现领域模型。

  1. 持续迭代开发

在DDD项目中,持续迭代开发是很重要的。将项目划分成多个小的迭代周期,每个周期都能完成一个或多个功能点的开发。通过迭代开发,逐渐完善领域模型并不断与业务需求进行验证和调整。

  1. 领域驱动的架构设计

DDD强调以领域模型为核心的架构设计。设计合适的架构模式,如六边形架构、CQRS(Command and Query Responsibility Segregation)等,以支持领域模型的实现和演进。

  1. 领域事件驱动

使用领域事件来解耦领域模型和外部系统之间的通信。通过使用事件驱动架构,可以实现松耦合、可伸缩的系统,并支持分布式系统的开发。

  1. 测试与验证

在DDD项目中,测试至关重要。编写针对领域模型的单元测试、集成测试和端到端测试,确保领域模型的正确性和稳定性。此外,需要与业务专家进行沟通和验证,确保领域模型符合业务需求。

  1. 持续优化

随着项目的进行,不断根据反馈和实际运行情况对领域模型进行优化和演进。根据项目的实际需求,可能需要对领域模型、限界上下文的划分、架构设计等进行调整和优化。

架构设计和模块划分

领域层 (Domain Layer):

💡领域层是 DDD 的核心,包含了对业务领域的建模和实现。在该层中,将关注点放在业务核心概念、规则和逻辑上。

主要包括以下模块:

  • 实体 (Entity):代表领域中的具体对象,具有唯一的标识符和状态。实体封装了业务行为和状态变化的逻辑。
  • 值对象 (Value Object):在领域层中用于描述某个特定概念的不可变对象。值对象没有唯一标识符,通常用于表示属性集合。
  • 聚合根 (Aggregate Root):聚合是一组关联对象的集合,聚合根是聚合中的一个主要对象。聚合根负责保证聚合内部的一致性和约束。
  • 领域服务 (Domain Service):处理领域对象之间的复杂业务逻辑,不属于任何一个具体的实体或值对象。
  • 领域事件 (Domain Event):表示在领域中发生的重要事实,用于捕获和传递领域内发生的变化。
应用层 (Application Layer)

应用层处理用户接口与领域层之间的交互,并协调不同的领域对象完成具体的应用需求。它负责接收用户输入,解析请求,调用领域对象的方法,并将结果返回给用户。

主要包括以下模块:

  • 应用服务 (Application Service):提供用户能直接调用的接口,负责接收用户请求、处理输入验证和异常处理,协调领域对象的协作。
  • 应用事件 (Application Event):用于在应用层中传播信息或通知,比如通知其他部分某个特定的事件已经发生。
基础设施层 (Infrastructure Layer)

基础设施层提供支持整个应用程序运行的基础设施服务,与具体的技术平台和框架相关。

  • 持久化层 (Persistence Layer):处理数据的持久化和访问,比如数据库访问、ORM 映射等。
  • 外部服务层 (External Service Layer):与外部系统进行交互的服务,比如第三方 API、消息队列、文件存储等。
  • UI 层 (User Interface Layer):处理用户接口的实现,包括 Web 页面、移动应用或其他用户界面。
共享内核 (Shared Kernel)

共享内核是一种可选的模块,用于处理多个子域之间共享的通用领域知识和组件。如果多个子域之间存在类似的业务逻辑或概念,可以将其抽象为共享内核,在不同的子域中共享和重用。

💡这些层次和模块之间通过严格的边界划分和通信机制来保持松耦合。领域层是 DDD 的核心,并且在架构设计中占据主导地位因为它直接与业务领域相关应用层负责协调和转换用户请求和领域对象之间的交互。基础设施层提供了支持整个应用程序的基础设施服务。共享内核用于处理多个子域之间的通用业务部分。

领域建模

💡领域驱动设计的核心在于领域建模,领域建模的主要目的是捕捉业务知识,形成统一语言,沉淀领域模型。好的领域建模就意味着对业务要有深刻的理解,能够洞察问题本质。

领域建模时,我们会根据场景分析过程中产生的领域对象,比如命令、事件等之间关系,找出产生命令的实体,分析实体之间的依赖关系组成聚合,为聚合划定限界上下文,建立领域模型以及模型之间的依赖。领域模型利用限界上下文向上可以指导微服务设计,通过聚合向下可以指导聚合根、实体和值对象的设计。

业务场景的分析

通过业务场景和用例找出实体,命令,事件。

建模步骤

  • 用例场景梳理:就是一句话需求,但我们需要把一些模糊的概念通过对话的方式逐步得到明确的需求,在加以提炼和抽象。
  • 建模方法论:词法分析(找名词和动词),领域边界
  • 模型验证
领域建模产出物
  • 领域模型:包含领域对象、属性、关系、行为、边界范围等各个方面,用于描述业务的本质,这也是最重要的产出物。
  • 用例图:用于明确系统的功能。
  • 数据模型:描述系统的数据结构和关系,包括实体关系模型、关系数据库模型等。
  • 状态图:用于描述系统各个状态及其转移条件。
  • 活动图:用于描述系统流程中的各个活动及其关系。
  • 序列图:描述系统中各个对象之间的交互过程和消息传递序列。
  • 架构模型:包含系统的物理和逻辑结构,包括组件、模块、接口等。

与微服务架构的结合

💡DDD(领域驱动设计)架构和微服务架构可以结合起来,以实现更灵活、可扩展和高内聚的系统设计。

  1. 微服务边界与子域边界对应

DDD 强调将复杂业务领域分解为子域,而微服务架构则将系统分解为一组小型自治服务。这两者都强调通过明确的边界来隔离和解耦各个功能模块。在结合时,可以将每个微服务与一个或多个子域对应起来,使每个微服务专注于特定的业务能力。

  1. 微服务作为应用层

在 DDD 中,应用层负责协调用户接口和领域层之间的交互。在微服务架构中,每个微服务都可以看作是一个独立的应用。因此,可以将微服务作为应用层来实现,负责处理用户请求、数据验证、事务处理等工作,并协调调用领域层的功能。

  1. 领域驱动设计在微服务中的体现

DDD 的核心概念如实体、值对象、聚合根和领域服务等,可以映射到微服务的实现中。每个微服务可以有自己的领域模型,负责实现特定子域的业务逻辑。微服务之间可以通过领域事件进行异步通信,以捕获和传递领域内发生的变化。

  1. 微服务的自治性和松耦合性

微服务架构鼓励每个服务的自治性,即每个服务可以独立开发、部署和扩展。在结合 DDD 时,每个微服务可以拥有自己的领域对象和业务规则,并通过领域事件或异步消息队列实现与其他微服务的解耦。这种松耦合性使得单个微服务的修改不会波及整个系统,提高了系统的可维护性和可扩展性。

  1. 按业务能力组织微服务

在 DDD 中,子域是按业务能力进行划分的,而微服务架构也强调遵循单一职责原则。因此,可以根据子域的边界和业务能力来组织微服务,每个微服务专注于一个或多个相关的业务能力。

  1. 分布式数据管理

微服务架构中,每个微服务都有自己的数据库或数据存储。在结合 DDD 时,每个微服务可以有自己的数据模型和数据访问层,负责管理自己的数据。需要注意确保数据的一致性和完整性,可以使用事件溯源或分布式事务等机制来处理跨微服务的数据一致性问题。

业务提炼

1、产品愿景

产品愿景是对产品的顶层价值设计,对产品目标用户、核心价值、差异化竞争点等信息达成一致,避免产品偏离方向。

2、场景分析

场景分析是从用户视角出发,探索业务领域中的典型场景,产出领域中需要支撑的场景分类、用例操作以及不同子域之间的依赖关系,用以支撑领域建模。

3、领域建模

领域建模是通过对业务和问题域进行分析,建立领域模型,向上通过限界上下文指导微服务边界设计,向下通过聚合指导实体的对象设计。

4、微服务拆分和设计

结合业务限界上下文与技术因素,对服务的粒度、分层、边界划分、依赖关系和集成关系进行梳理,完成微服务拆分和设计。

微服务设计应综合考虑业务职责单一、敏态与稳态业务分离、非功能性需求(如弹性伸缩要求、安全性等要求)、团队组织和沟通效率、软件包大小以及技术异构等因素。

微服务设计原则
  1. 要领域驱动设计,而不是数据驱动设计,也不是界面驱动设计

微服务设计首先应建立领域模型,确定逻辑和物理边界后,然后才进行微服务边界拆分,而不是一上来就定义数据库表结构,也不是界面需要什么,就去调整领域逻辑代码。

领域模型和领域服务应具有高度通用性,通过接口层和应用层屏蔽外部变化对业务逻辑的影响,保证核心业务功能的稳定性。

  1. 要边界清晰的微服务

微服务完成开发后其功能和代码也不是一成不变的。随着需求或设计变化,微服务内的代码也会分分合合。逻辑边界清晰的微服务,可快速实现微服务代码的拆分和组合。DDD思想中的逻辑边界和分层设计也是为微服务各种可能的分分合合做准备的。

微服务内聚合与聚合之间的领域服务以及数据原则上禁止相互产生依赖。如有必要可通过上层的应用服务编排或者事件驱动机制实现聚合之间的解耦,以利于聚合之间的组合和拆分。

  1. 要职能清晰的分层

分层架构中各层职能定位清晰,且都只能与其下方的层发生依赖,也就是说只能从外层调用内层服务,内层服务通过封装、组合或编排对外逐层暴露,服务粒度由细到粗。

应用层负责服务的编排和组合,领域层负责领域业务逻辑的实现,基础层为各层提供资源服务。

  1. 要做自己能掌握住的微服务,而不是过度拆分的微服务

微服务的过度拆分必然会带来软件维护成本的上升,如:集成成本、运维成本以及监控和定位问题的成本。企业转型过程中很难短时间内提升这些能力,如果项目团队不具备这些能力,将很难hold住这些过细的微服务。而如果我们在微服务设计之初就已经定义好了微服务内的逻辑边界,项目初期我们可以尽可能少的拆分出过细的微服务,随着技术的积累和时间的推移,当我们具有这些能力后,由于微服务内有清晰的逻辑边界,这时就可以随时根据需要轻松的拆分或组合出新的微服务。

方法

第一步: 按照业务流程(通常适用于核心域)或者功能属性、集合(通常适用于通用域或支撑域),将业务域细分为多个中台,再根据功能属性或重要性归类到核心中台或通用中台。核心中台设计时要考虑核心竞争力,通用中台要站在企业高度考虑共享和复用能力。

第二步: 选取中台,根据用例、业务场景或用户旅程完成事件风暴,找出实体、聚合和限界上下文。依次进行领域分解,建立领域模型。 由于不同中台独立建模,某些领域对象或功能可能会重复出现在其它领域模型中,也有可能本该是同一个聚合的领域对象或功能,却分散在其它的中台里,这样会导致领域模型不完整或者业务不内聚。这里先不要着急,这一步我们只需要初步确定主领域模型就可以了,在第三步中我们还会提炼并重组这些领域对象。

第三步: 以主领域模型为基础,扫描其它中台领域模型,检查并确定是否存在重复或者需要重组的领域对象、功能,提炼并重构主领域模型,完成最终的领域模型设计。

第四步: 选择其它主领域模型重复第三步,直到所有主领域模型完成比对和重构。

第五步: 基于领域模型完成微服务设计,完成系统落地。

代码目录

Interfaces(用户接口层):本目录主要存放用户接口层代码。前端应用通过本层向应用服务获取展现所需的数据。本层主要用于处理用户发送的Restful请求和解析用户输入的配置文件等,并将信息传递给Application层。主要代码形态是数据组装以及Facade接口等。

Application(应用层):本目录主要存放应用层代码。应用服务代码基于微服务内的领域服务或微服务外的应用服务完成服务编排和组合。为用户接口层提供各种应用数据展现支持。主要代码形态是应用服务和领域事件等。

Domain(领域层):本目录主要存放领域层代码。本层代码主要实现核心领域逻辑,其主要代码形态是实体类方法和领域服务等。

Infrastructure(基础层):本目录存放基础层代码,为其它各层提供通用技术能力、三方软件包、配置和基础资源服务等。

DDD 架构的挑战和解决方案

复杂性和团队协作的问题

复杂性和团队协作是软件开发中普遍面临的挑战,尤其在大型项目中更为突出。

复杂性问题
  • 难以理解和管理:大规模软件系统通常涉及多个子系统和模块,其交互复杂度很高。代码的可读性和可维护性受到挑战。
  • 高度耦合和依赖:不良的设计和实现可能导致组件之间紧密耦合,修改一个模块可能会影响其他模块,导致维护和扩展困难。
  • 技术栈和工具的选择:需要评估和选择适合项目需求的技术栈和工具,使得系统开发过程更加高效和可维护。
团队协作问题
  • 沟通和协调:在大型项目中,多个团队成员之间的协作和沟通变得更加困难,需确保有效的信息共享和沟通渠道。
  • 角色和责任:明确团队成员的角色和责任,确保每个人知道自己的任务和目标,避免任务冲突和重复工作。
  • 分布式团队:如果团队分散在不同地区或时区,协作可能会更具挑战性。需要采用合适的工具和流程来促进远程团队成员之间的协作和沟通。
应对方法
  1. 使用适当的架构和设计模式:通过使用合适的架构和设计模式,可以将系统分解为更小的、可管理的组件,并减少模块之间的耦合度。
  2. 引入自动化测试和持续集成:使用自动化测试和持续集成工具,确保代码质量和系统稳定性,并及早发现和解决问题。
  3. 实践敏捷开发方法:采用敏捷开发方法,如Scrum或Kanban,以增加透明度、灵活性和反馈,促进团队合作和快速响应变化。
  4. 建立清晰的沟通渠道:确保团队成员之间有良好的沟通和信息共享机制,例如定期的会议、沟通工具和文档分享。
  5. 高效的项目管理:使用适当的项目管理工具和技术,跟踪任务进度、资源分配和风险管理,以确保项目按时交付和团队协作高效。
  6. 持续学习和知识分享:鼓励团队成员进行持续学习,通过内部培训、技术分享会等方式提高技能水平和知识共享。

面向领域的测试和自动化测试策略

DDD 面向领域的测试策略
  • 业务规则测试:测试业务规则是否按预期工作,涉及验证各种业务规则的正确性。
  • 聚合根测试:聚合根是 DDD 中的核心概念,测试应确保聚合根的行为和状态正确,并与其关联的实体、值对象及领域事件进行适当的交互和更新。
  • 领域服务测试:领域服务负责处理领域中的复杂业务逻辑,测试要验证领域服务能够正确执行其职责。
  • 领域事件测试:测试领域事件的产生、发布和处理,确保领域事件在系统中正确地传播和触发相关操作。
  • 领域模型一致性测试:验证领域模型的一致性和完整性,确保模型在各种场景下的正确行为。
自动化测试策略
  • 单元测试:通过编写单元测试用例,测试领域对象、聚合根、值对象等的行为和状态,并确保它们按预期工作。
  • 集成测试:测试多个领域对象或服务之间的集成,验证它们在协同工作时的正确性。
  • 接口测试:测试与外部系统或服务的接口交互,确保数据传输和通信的准确性和稳定性。
  • 持续集成测试:将自动化测试纳入持续集成流程,确保每次代码提交后都能进行自动化测试,从而及早发现问题并减少回归测试的工作量。
✨注意事项
  • 确保测试覆盖率:尽可能涵盖业务领域的各个方面,以减少遗漏的测试场景。
  • 使用适当的测试框架和工具:选择适合领域驱动设计的测试框架和工具,例如基于 BDD(行为驱动开发)的测试框架,如Cucumber或SpecFlow。
  • 注重测试数据:测试数据在 DDD 测试中至关重要,应该考虑各种不同的情况,包括边界条件、异常情况等。
  • 与领域专家紧密合作:与业务领域专家进行密切的合作和沟通,以确保测试场景和用例与业务需求一致。
  • 持续改进:根据测试结果和反馈不断改进测试策略和自动化测试框架,提高测试质量和效率。

DDD结构战略设计与战术设计

在DDD中可以分为战略设计和战术设计,各自包含的内容如下图所示:

战略设计

战略设计指的是对整个领域进行分析和规划,确定领域中的概念、业务规则和领域边界等基础性问题。在战略设计中,需要对领域进行全面的了解和分析,探究业务的规则和本质,并且需要考虑到领域的未来发展趋势和可能的变化。领域、子域和限界上下文属于战略设计的范畴。

领域

领域(Domain)其实就是一个组织所要做的整个事情,以及这个事情下所包含的一切内容。这是一个范围概念,而且是面向业务的(注意这里不是面向技术的,更不是面向数据库的持久化的),每个组织都有自己的人员、规则和流程,当你为该组织开发软件的时候,你面对的就是这个组织的领域。

子域

子域是指在一个大的领域中,可以进一步划分出来的独立的业务子领域,它们有着自己的业务概念、规则和流程等。

为了区分重要性的不同,我们又会将子域划分成核心域、通用域以及支撑域。

核心域

决定公司和产品核心竞争力的子域就是核心域,它是业务成功的主要因素。核心域直接对业务产生价值。

通用域

没有太多个性化的诉求,同时被多个子域使用的、具有通用功能的子域就是通用域。通用域间接对业务产生价值。

支撑域

支撑其他领域业务,具有企业特性,但不具有通用性。支撑域间接对业务产生价值。

限界上下文

限界上下文就是业务边界的划分,这个边界可以是一个子域或者多个子域的集合。如何进行划分,一个行之有效的方法是一个界限上下文必须支持一个完整的业务流程,保证这个业务流程所涉及的领域都在一个限界上下文中。限界上下文是微服务拆分的依据,即每个限界上下文对应一个微服务。

战术设计

战术设计则是在战略设计的基础上,对领域中的具体问题进行具体的解决方案设计。战术设计关注的是领域中的具体情境和场景,需要针对具体的问题进行具体的分析和设计,以满足业务需求。实体、值对象、聚合、工厂、资源库、领域服务和领域事件就属于战术设计的范畴。

实体(Entity)
定义
  • 实体是具有唯一标识的具体领域对象,它具有生命周期且有延续性、可以拥有状态和行为,并且可以与其他实体进行交互。
  • 实体通过标识属性来区分不同的对象,并且可以根据业务规则进行状态变化和行为操作。
  • 实体是具有唯一标识的具体领域对象,它具有生命周期且有延续性、可以拥有状态和行为,并且可以与其他实体进行交互。
  • 实体通常具有持久性,需要被保存到数据库或其他存储介质中。
  • 实体能够反映业务的真实形态,是从用例提取出来的。领域模型中的实体是多个属性、操作或行为的载体。
  • 实体可以直接参与业务规则的验证和执行,它负责维护自身的状态和行为,并与其他实体进行交互。
  • 实体可以有自己的属性和方法,通常属于某个聚合,并且在聚合内部起到具体的角色,可以通过消息传递和调用方法来实现与其他实体的协作和交互。

实体的代码形态一般有四种形态:

  • 贫血模型(Anemic Domain Model)是指将业务逻辑主要放在服务对象中,而领域对象(实体、值对象等)则只具备数据和基本操作,缺乏自身的行为。包含了一些业务逻辑,但不包含依赖持久层的业务逻辑。这部分依赖于持久层的业务逻辑将会放到服务层中。这种模型会导致业务逻辑分散和难以维护。
  • 充血模型(Rich Domain Model)是指将业务逻辑尽可能地放在领域对象中,使其具备自身的行为和状态。包含了所有的业务逻辑,包括依赖于持久层的业务逻辑。这种模型可以更好地保护业务规则,提高内聚性和可维护性。
  • 失血模型:模型仅仅包含数据的定义和getter/setter方法,业务逻辑和应用逻辑都放到服务层中。这种类在Java中叫POJO。
  • 胀血模型:胀血模型就是把和业务逻辑不想关的其他应用逻辑(如授权、事务等)都放到领域模型中。

结合团队以及兄弟团队的实践,建议实体采用贫血模型,实体和领域服务共同构成领域模型。这样可以使得实体具备业务知识,但又不至于太过臃肿。

实体的特点和使用
  • 实体应该具有唯一标识,通过标识来区分不同的对象。
  • 实体的行为和状态应该与其标识关联,尽可能在实体内部处理业务规则和状态变化。
  • 实体之间可以通过引用和关联进行交互。
作用
  • 表示业务领域中的具体概念和对象
  • 维护自身的状态和行为
  • 参与聚合内部的业务规则的执行和数据的变更
  • 与其他实体进行交互和协作
值对象(Value Object)
定义

通过对象属性值来识别的对象,它将多个相关属性组合为一个概念整体。在 DDD 中用来描述领域的特定方面,并且是一个没有标识符的对象。值对象没有唯一标识,没有生命周期,不可修改,当值对象发生改变时只能替换。值对象通常被用于聚合内部,作为实体的属性或者组成聚合根的一部分。

业务形态

大多数情况下实体具有很多属性,这些属性一般都是平铺,但有的属性进行归类和聚合后能够表达一个业务含义,就将这些属性封装到一起形成值对象,从而方便沟通而无需关注细节,因此可以说值对象就是用来描述实体的特征。当然实体的单一属性也是值对象。

代码形态

值对象有两种:单一属性的值对象,例如字符串、整型、枚举等;多个属性的值对象,这时候设计成class,包含多个属性,但是没有ID,值对象中可以嵌套值对象。

值对象的特点和使用
  • 值对象应该是不可变的,即创建后不可修改其属性值,任何修改都应该创建一个新的值对象。
  • 值对象是用于描述某个特定概念的不可变对象,没有唯一标识,不可变且没有生命周期的对象,仅仅通过其属性值来区分不同的对象。
  • 值对象重点关注其属性的语义,而不是标识,通常具有更精简的行为,只包含基本的访问方法。
  • 值对象一般不具有持久性,也不需要被单独保存到数据库中,它通常用来表示领域中的某个值或属性,并且可以作为实体的属性或参数。
  • 值对象通过封装自身的状态来保证数据的一致性和完整性,提供相等性判断和对外不可变等特性。
  • 值对象的行为不会产生副作用,对其的操作不会改变系统的状态。
作用
  • 封装重复的属性,提高代码可读性和可维护性。
  • 提供了一种更加表达领域概念的方式,增强了代码的语义性。
  • 作为实体的属性,帮助实体建立复杂的关联关系。
  • 支持领域行为的建模和封装。
实体和值对象的区别和选择
  • 实体是具有生命周期和标识的,适合表示具有独立生命周期和状态变化的对象。
  • 值对象是没有生命周期和标识的,适合表示不可变的、相对简单的概念。
  • 在建模过程中,根据具体的业务需求和概念的本质,选择合适的实体或值对象来表示。
实体和值对象的关系
  • 实体可以包含值对象作为其属性,用于描述实体的某些属性或特征。
  • 实体和值对象之间可以存在聚合关系,即实体可以作为聚合根,拥有一组相关的实体和值对象。
聚合和聚合根

💡DDD(领域驱动设计)中的聚合根和聚合模式是一种重要的设计概念,用于管理和维护领域对象之间的整体性和一致性。

聚合是一种更大范围的封装,把一组有相同生命周期、在业务上不可分隔的实体和值对象放在一起考虑,只有根实体可以对外暴露引用,这个根实体就是聚合根,聚合也是一种内聚性的表现。

领域、子域、限界上下文、聚合都是用来表示一个业务范围,那他们的关系是怎样的呢?领域、子域、限界上下文属于战略设计,而聚合属于战术设计,聚合的范围是小于前三者的,范围大小图如下:
 

聚合模式(Aggregate Pattern)
  • 是一种将一组相关的领域对象组织成聚合的方式,以实现整体性和一致性的管理。
  • 由聚合根和聚合内的对象组成,聚合根负责管理和控制聚合内的对象,维护其状态一致性。
  • 通过将领域对象划分为聚合根、实体和值对象等层次结构,以及定义聚合根的边界和关联关系,来约束对象之间的访问和操作。
  • 强调封装和隐藏聚合内部对象,通过聚合根提供的方法来管理聚合的行为和状态。
聚合内部对象的定义和访问
  • 聚合内部的对象可以包括实体、值对象和其他聚合根,根据具体业务需求来设计和划分。
  • 聚合内部对象应该被封装起来,不直接暴露给外部对象。
  • 外部对象通过聚合根提供的方法来间接访问和操作聚合内部的对象。
聚合之间的关系和边界
  • 聚合之间可以存在嵌套和引用关系,形成复杂的领域模型网。
  • 每个聚合根应该有清晰的边界,以限制不同聚合之间的直接访问和操作。
  • 聚合之间的关系应该通过聚合根的标识属性和引用属性来建立。
聚合根(Aggregate Root)
  • 是领域模型中的一个重要概念,它是一组相关对象的根节点,代表了一个整体的概念或实体。
  • 负责维护聚合内部的一致性和完整性,并提供对聚合内部对象的访问和操作。
  • 通过封装内部的实体、值对象和关联关系,形成一个边界,它定义了聚合的边界和访问规则。
  • 通常具有全局唯一的标识,可以通过该标识来标识和访问整个聚合。
  • 通过标识属性来唯一标识一个聚合实例,并将聚合内部的对象封装在其内部。
  • 作为聚合的入口点,通过公开的方法来处理聚合内部的业务逻辑和行为。
  • 外部对象应该通过聚合根来访问和操作聚合内的对象,而通过聚合根提供的方法来间接操作聚合内部对象,以保证聚合的整体性。
  • 负责管理和维护聚合内的对象之间的关系和一致性。
作用
  • 约束整个聚合的一致性和完整性
  • 提供对聚合内部对象的访问和操作
  • 封装聚合内部的复杂关联关系和业务规则
  • 作为聚合的接口,与外部系统进行交互

总结:聚合根是领域模型中一组相关对象的根节点,它负责维护整个聚合的一致性和完整性;而实体是具体的业务概念和对象,代表了聚合内部的一个具体实例,它负责维护自身的状态和行为,并与其他实体进行交互。聚合根和实体在领域模型中具有不同的定义和作用,它们协同工作,构建出强大而灵活的领域模型,提供了一种可靠的方法来处理复杂的业务需求。

工厂

工厂是一种重要的设计模式,DDD只是拿来主义,用到了工厂。考虑使用工厂的主要动机:

将创建复杂对象和聚合的职责分配给一个单独的对象,该对象本身并不承担领域模型中的职责,但是依然是领域设计的一部分。工厂应该提供一个创建对象的接口,该接口封装了所有创建对象的复杂操作过程,同时,它并不需要客户去引用那个实际被创建的对象。对于聚合来说,我们应该一次性地创建整个聚合,并且确保它的不变条件得到满足。

资源库

资源库(Repository)是一种模式,用于封装数据访问逻辑,提供对数据的持久化和查询。它旨在将数据访问细节与领域模型分离,使领域模型更加独立和可测试。资源库提供了一种统一的接口,使得领域模型可以与不同的数据存储方式(如关系数据库、文档数据库、内存数据库等)进行交互,同时也提供了一些查询操作,以便在领域层中进行数据查询。如果我们使用MyBatis的话,Mapper就是对资源库的一种实现。

领域服务

有些领域中的动作看上去并不属于任何对象。它们代表了领域中的一个重要的行为,不能忽略它们或者简单地把它们合并到某个实体或者值对象中。当这样的行为从领域中被识别出来时,推荐的实践方式是将它声明成一个服务,这个服务就是领域服务。

领域事件

领域事件是发生在领域中且值得注意的事件。而领域事件通常意味着领域对象状态的改变。领域事件在系统中起到了传递消息、触发其他动作的作用,是解耦领域模型的重要手段之一。我们往往利用消息队列来传递领域事件。

  • 13
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值