如何进行DDD领域驱动设计的工程化实施但目前还没有涉及到工程层面的落地。所有这些架构理论或设计模式最终都是为了让我们的代码结构更清晰、更可扩展和可维护。这样可以开发出bug更少、稳定性更好的应用。因此,本文重点介绍如何实现DDD工程化实施。DDD领域分层当我们完成了边界上下文的划分和领域模型的构建之后,我们需要设计微服务的工程结构。在实现工程结构之前,我们需要确定微服务内部的域层次结构。首先我们要思考一个问题,为什么要进行领域分层?其实领域分层是一种分而治之的思想,主要是为了避免把代码项目开发成一个大泥球。各种业务复杂逻辑和技术细节混杂在一起,导致项目后期难以维护,也削弱了领域模型。正直。此外,通过领域分层设计,更容易开发出高内聚、低耦合的软件服务,在模块重用和可扩展性方面也会有更好的表现。弄清楚领域为什么要分层之后,我们来确定微服务内部如何实现领域分层,因为分层设计的好坏直接决定了我们微服务工程结构的合理性和后期团队实现的效果.但遗憾的是,真正的领域驱动设计对于如何规范工程结构并没有非常清晰具体的规范,所以需要我们根据自己的实践经验、思考和理解来划分设计。下图左边的分层方式是EricEvans在《领域驱动设计》中提出的,但是这种分层方式其实有明显的不足。你为什么这么说?MVC的开发方式大家都很熟悉,所以在团队中实现DDD的时候,很多同学都会有疑问,为什么基础设施层要反向依赖领域层,大家觉得很别扭。按照正常的逻辑,领域模型发生变化后,需要持久化。很明显,领域层依赖于基础设施层,但是当项目实施时,基础设施层仍然依赖于领域层。为什么是这样?其实不管是哪种架构,都是遵循这个设计原则的。我们都认为业务领域是核心领域,核心领域的外部依赖越少越好。因此,有必要将技术复杂性与业务复杂性分开。那么在基于DDD的架构中,领域层是核心层,所以它的外部依赖越少越好,也就是说应该是非核心依赖核心而不是核心依赖非-核。在我们之前的开发模式中,一般都是通过服务接口来调用dao接口进行相关的数据操作,但是我们发现一旦进行了一些优化操作,比如增加缓存来提高数据查询的效率,我们就需要修改服务层的代码,但其实加缓存是一个技术实现细节,不在业务范围内,但实际情况是技术细节的变化会影响到业务层,所以这种情况显然是不合理的。因此,上图优化后的依赖倒置,表面上看是基础设施层依赖领域层,其实质是技术实现细节依赖接口抽象,是一种编程思维的转变。repo层的接口定义在领域层,具体的实现细节由基础实现层完成,实现了技术实现细节的解耦。同时,既保证了领域层模型的稳定性,又提高了基础设施层实现的灵活性。各层模型数据对象在介绍各层对象之前,我们先来思考一个问题。为什么每一层都有不同的数据模型对象?不同层调用接口时,每次都需要转换模型对象。在许多情况下,对象中的参数仍然相同。这样做不是多余的吗?这也是我在团队中实现DDD领域驱动设计时很多同学提出的问题。但是你有没有想过一个问题,假设我们在代码中使用一个模型数据对象来连接各个层,如果有一天数据库表字段被增加或者修改,那么这个变化就会在每一层传播,这样,甚至如果应用是分层的,其实和一个大泥球的应用没什么区别。此外,对于核心领域层,还需要屏蔽底层细节变化对领域模型的影响,避免领域模型稳定性问题。因此,为了避免上述问题,每一层都应该有自己的模型数据对象,各司其职。VO(ViewObject,视图对象):该层视图数据对象的主要作用是将应用层的数据进行组装,形成页面展示的数据。DTO(DataTransferObject,数据传输对象):DTO主要作为Application层的输入输出参数,用于用户界面层和应用层之间的数据传输。比如接口参数中的Command、Query、Event,以及Request、Response等,都属于DTO的范畴。DTO的价值在于适配不同业务场景的输入输出参数,避免把业务对象变成一个通用的大对象。模型(领域对象):领域对象就是我们常说的核心领域模型对象。无论采用何种持久化方法,其字段和方法都应具有强大的业务语义。也就是说,Entity和PO很可能有着完全不同的字段名和字段类型,甚至是嵌套关系。实体的生命周期应该只存在于内存中,不需要可序列化和持久化。PO(PersistentObject,持久化对象):其实是我们日常工作中最常见的数据模型。但在DDD规范中,PO应该只是作为物理数据库表的映射,不能参与业务逻辑。为了简单明了,PO的字段类型和名称应该对应数据库物理表的字段类型和名称,这样我们就不用去数据库里查某个字段的类型和名称了.各个层次的数据流上文已经提到了领域层级以及各个数据对象的不同含义和用途,下面我们来看看各个数据对象在DDD的各个领域层是如何进行数据流转的。在用户界面层,需要接收来自WEB、APP等的外部数据请求,通过DTO将请求传递给应用层。根据应用层返回的DTO数据,将DTO转换为页面需要呈现的VO。数据。我们通过Query对象来表示查询,通过Command对象来表示数据操作。当请求到达应用层时,如果我们需要调用对外服务的接口,需要通过应用层的防腐层来调用。为什么需要防腐层?主要目的是隔离变化,防止外部服务的数据变化影响应用层的代码。如果实在需要修改,直接在防腐层修改就好了。在领域层,我一般使用model,可以理解为业务领域模型,主要包括实体和值对象。在应用层,模型会作为参数调用领域层的接口,完成核心业务逻辑。在其他一些书上,很多人喜欢用DO作为domain层的数据承载对象,但我个人认为model更合适,因为从名字上看更容易理解也更直观。领域层包含存储接口,具体实现在基础设施层。这是一种依赖倒置的设计方法,实现了领域层和基础层的解耦。数据转换的大致流程如下图所示。工程结构落地在领域层确定了各层的依赖关系后,我们需要设计一个具体的可以实现的工程结构,如下图所示。Starter层:这一层属于用户界面层,服务的启动类也在这一层,主要负责启动服务,对外提供REST接口或RPC接口。业务层:主要负责业务逻辑的编排,不负责具体的业务逻辑,所以这一层应该比较薄。集成层:ACL层,即防腐层,主要与对外服务接口进行交互。它的存在主要是为了将微服务自身的业务模型与外部服务的模型进行隔离,防止外部服务模型的变化影响到自身的服务领域模型。稳定。领域层:领域层属于核心层。所有的业务领域模型和领域服务都在这一层,沉淀了整个业务领域的业务领域模型。也就是说,核心业务逻辑落在这一层,同时定义了repository。层接口。commonlayer:公共层,主要包含一些支持其他业务的代码,比如各种工具类,各种常量定义,错误码定义,多种语言等。Repository层:属于基础设施层,主要负责与数据库、Redis等交互,实现领域层定义的接口。综上所述,本文主要和大家聊了如何实现DDD领域驱动设计,分析了为什么需要领域分层以及为什么要实现依赖倒置的领域分层结构,同时基于领域分层结构依赖倒置,一个可登陆的微服务工程结构。希望本文能为大家在实现DDD时的工程结构设计提供一些思路。下面几篇文章将从代码层面出发,与大家分享如何通过代码实现DDD。
