DDD项目实践

2023-05-14  本文已影响0人  lotusfan2018

前言

领域驱动设计(DDD)是一种软件开发方法论,其核心思想是将业务领域的知识和业务逻辑融入到软件设计和开发中,以实现更加符合业务需求和更易于维护的软件系统。

在传统的软件开发方法中,开发人员往往关注的是技术实现而非业务领域本身。而在DDD的方法论中,开发人员需要与业务专家紧密合作,深入了解业务领域,将业务领域的知识和业务逻辑转化为软件设计和开发中的概念和实现。

DDD的核心概念包括:

通过将业务领域的知识和业务逻辑融入到软件设计和开发中,DDD可以帮助开发人员实现更加符合业务需求的软件系统,并提高软件系统的可维护性、可扩展性和可测试性。

一、从六边形架构谈起

六边形架构是一种软件架构,用于为每种外部类型提供一个适配器。它可以帮助我们从新的角度来看待整个系统,并将系统分为外部区域和内部区域两个部分。

外部区域是指处理不同客户端的输入请求的部分。它包含了各种适配器,用于将不同类型的客户输入转化为程序内部API所理解的输入。在六边形架构中,每种类型的客户都有自己的适配器。其中,每种适配器对应着一个不同种类型的端口,端口要么处理输入,要么处理输出。无论采用哪种方式对端口进行划分,当客户请求到达时,都应该有相应的适配器对输入进行转化,然后适配器将调用应用程序的某个操作或者向应用程序发送一个事件,控制权由此交给内部区域。

内部区域是指负责处理持久化数据并对程序输出进行存储和转发的部分。它包含了应用层,领域层和基础设施层。

六边形架构是一种非常灵活和通用的架构,可以帮助我们更好地组织和管理大型软件系统。

Untitled.png

二、依赖倒置

依赖倒置原则(DIP)由Robert C. Martin提出,其核心定义如下:

根据DIP原则,领域层可以不再依赖于基础设施层,基础设施层通过注入持久化实现完成对领域层的解耦。采用依赖注入原则的新分层架构模型如下:

Untitled 1.png

采用依赖注入方式后,我们可以发现实际上已经没有分层概念了。无论是高层还是底层,都只依赖于抽象,整个分层结构被推平了。

三、聚合

在DDD中,聚合是指一组具有内聚性的实体和值对象的集合。它们共同形成了一个有边界的上下文,这个上下文可以看作是一个单个的单元。这个单元可以通过聚合根(Aggregate Root)进行访问和修改,聚合根是聚合中的唯一访问点。聚合根担任了保护聚合内部完整性和一致性的角色。

聚合的设计目的是保持领域模型的内聚性和一致性。将相关实体和值对象聚合在一起,可以更好地保护和管理领域模型,减少了并发冲突的可能性,提高了系统的可维护性。

在聚合内部,实体和值对象的访问应该受到限制,只能通过聚合根进行访问。这个限制可以通过使用封装和访问控制等技术来实现。聚合根应该提供足够的方法来支持聚合的业务需求,同时也应该避免暴露过多的实现细节。

在设计聚合时,需要注意以下几个原则:

  1. 通过一致性边界内建模真正的不变条件来封装实体的不变性,实现对象数据的一致性。该原则保证了聚合的业务高内聚性。
  2. 采用设计小聚合的方式来降低实体之间管理的复杂性,避免高并发操作带来的冲突和数据库锁等问题。小聚合设计也提高了领域模型的适应性,以适应业务变化。
  3. 通过唯一标识引用其它聚合,避免直接对象引用的方式。该原则减少了聚合之间的耦合度,避免聚合边界不清晰的问题。
  4. 在边界之外使用最终一致性,保证聚合内部数据的强一致性,而聚合之间数据的最终一致性。该原则通过异步修改相关聚合的领域事件来实现聚合之间的解耦。
  5. 通过应用层实现跨聚合的服务调用,避免跨聚合的领域服务调用和跨聚合的数据库表关联。该原则实现了微服务内聚合之间的解耦,支持未来以聚合为单位的微服务组合和拆分。

聚合根、实体、值对象

在DDD中,聚合是一组相关的对象的集合,它们具有内在的一致性和完整性规则,并且共享一个边界。

四、DDD 分层

整体架构图

Untitled 2.png

整体代码结构

ddd-domin
├── pom.xml
└── src
    └── main
        └── java
            └── org
                └── example
                    ├── App.java
                    ├── adapter
                    │   ├── market
                    │   └── product
                    │       ├── kafka
                    │       │   └── ProductConsumer.java
                    │       ├── socket
                    │       │   └── ProductSocket.java
                    │       └── web
                    │           └── ProductController.java
                    ├── application
                    │   ├── event
                    │   │   ├── EventManager.java
                    │   │   └── IEvent.java
                    │   ├── market
                    │   └── product
                    │       ├── ProductFactory.java
                    │       ├── ProductService.java
                    │       ├── command
                    │       │   ├── AddCountProductCommand.java
                    │       │   └── CreateProductCommand.java
                    │       ├── dto
                    │       │   └── ProductDTO.java
                    │       ├── event
                    │       │   ├── AbstractProductEvent.java
                    │       │   ├── AddNumProjectEvent.java
                    │       │   └── CreateProjectEvent.java
                    │       └── mapstruct
                    │           └── ProductStruct.java
                    ├── common
                    │   └── exception
                    │       └── BusException.java
                    ├── domain
                    │   ├── market
                    │   ├── product
                    │   │   └── Product.java
                    │   └── repository
                    │       ├── IProductRepository.java
                    │       └── entity
                    │           └── ProductEntity.java
                    └── infrastructure
                        ├── cache
                        ├── repository
                        │   └── impl
                        │       └── ProductRepositoryImpl.java
                        └── sqlmapper

3.1 用户接口层

用户接口层作为对外的门户,将网络协议与业务逻辑解耦。它是整个系统的重要组成部分,可以包含如下内容:


在项目应用中,用户接口层仅负责封装协议请求的处理,鉴权、Session管理和限流等其他任务则由独立的应用程序负责。这种设计方法确保了用户接口层不会负担过多的额外职责,使其可以专注于处理请求和响应。通过将鉴权、Session管理和限流等任务委托给独立的应用程序,整个系统可以更好地组织和更加灵活,从而更易于维护和扩展。

3.2 应用层

应用层是整个系统的业务逻辑层,是领域层和用户接口层之间的桥梁。应用层接收用户的请求,调用领域层模型和服务完成业务逻辑,然后将结果返回给用户接口层。应用层可以包含如下内容:

3.3 领域层

领域层是整个系统的核心,它包含了系统的业务规则和业务逻辑。领域模型是领域层的核心,它是对业务领域的建模。领域层可以包含如下内容:


在我们的项目中,我们遵循领域驱动设计(DDD)的方法,并在不同层之间进行了明确的关注点分离。Repository 层仅负责处理聚合根相关的操作,而不是查询。因此,我们决定将查询从应用层直接连接到基础设施层。通过这样做,我们确保领域层可以更专注于实体操作,而不会被查询所干扰。

将查询移到基础设施层中允许我们在实现和可扩展性方面具有更大的灵活性。我们可以选择最适合处理查询的技术,并优化系统的性能。

总的来说,这个设计决策通过分离职责并确保每一层都有明确的目的,提供了一个更健壮和可维护的系统。

3.4 基础设施层

基础设施层是整个系统的基础设施,它包含了与具体技术相关的代码和逻辑。基础设施层可以包含如下内容:

上一篇 下一篇

猜你喜欢

热点阅读