DDD全网最通俗易懂讲解(三)

DDD代码模型

img

Interfaces(用户接口层):他主要存放用户接口层与前端交互,展现数据相关的代码。前端应用通过这一层的接口,向应用服务获取展现所需的数据。这一层主要用来处理用户发送restful请求,解析用户输入的配置文件,并将数据传递给Application层,数据的组装,数据传输格式以及Facade接口等代码都会放在这一层目录中

Applicaiton(应用层):他主要存放应用层服务组合和编排相关的代码,应用服务向下基于微服务内的领域服务或外部服务的额应用服务完成服务的编排和组合,向上为用户接口层提供各种应用数据展现支持服务,应用服务和事件等代码会放在这一层目录里

Domain(领域层):他主要存放林谷层核心业务逻辑相关的代码。领域层可以包含多个聚合代码包,他们共同实现领域模型的核心业务逻辑。聚合以及聚合内的实体,方法,领域服务和事件等代码会放在这一层目录里

infrastructure(基础层):他主要存放基础资源服务相关的代码,为其他各层提供的通用技术能力,三方软件包,数据库服务,配置和基础资源服务的代码都会放在这一层勎目录里

用户接口层

Interfaces 的代码目录结构有:assembler、dto 和 facade 三类。

img

Assembler:实现DTO与领域对象之间的相互转换和数据交换。一般来说Assembler与DTO总是一同出现。

DTO:他是数据传输的载体,内部不存在任何业务逻辑,我们可以通过DTO把内部的领域对象与外界隔离

Facade:提供较粗粒度的调用接口,将用户请求委派给一个或多个应用服务进行处理哦

应用层

Application 的代码目录结构有:event 和 service。

img

Event(事件):这层目录主要存放事件相关的代码。它包含两个子目录:Publsh和subscribe。前者主要存放时间发布相关代码,后者主要存放事件订阅相关代码(事件处理相关的核心业务逻辑在领域层实现)这里提示一下:虽然应用层和领域层都可以进行事件的 发布和处理,但为了实现事件的统一管理我建议你将微服务内所有事件的发布和和订阅的处理统一放到应用层,时间相关的核心业务逻辑实现都放在领域层,通过应用层调用领域层服务,来实现完整的事件发布和订阅处理流程

Service(应用服务):这层的服务是应用服务 ,应用服务会对多个领域服务或外部应用服务进行封装、编排和组合,对外提供粗粒度的服务。应用服务主要实现服务组合和编排,是一段独立的业务逻辑,你可以将所有应用服务放在一个应用服务类,也可以把一个应用服务设计为一个应用服务类,以防应用服务类代码质量过大。

领域层

Domain 是由一个或多个聚合包构成,共同实现领域模型的核心业务逻辑。聚合内的代码模型是标准和统一的,包括:entity、event、repository 和 service 四个子目录。

img

Aggregate(聚合):它是聚合软件包的根目录,可以根据实际项目的聚合名称命名,比如权限聚合。在聚合内定义聚合根、实体和值对象以及领域服务之间的关系和边界。聚合内实现高内聚的业务逻辑,它的代码可以独立拆分为微服务。以聚合为单位的代码放在一个包里的主要目的是为了业务内聚,而更大的目的是为了以后微服务之间聚合的重组。聚合之间清晰的代码边界,可以让你轻松地实现以聚合为单位的微服务重组,在微服务架构演进中有着很重要的作用。

Entity(实体):它存放聚合根、实体、值对象以及工厂模式(Factory)相关代码。实体类采用充血模型,同一实体相关的业务逻辑都在实体类代码中实现。跨实体的业务逻辑代码

在领域服务中实现。

Event(事件):它存放事件实体以及与事件活动相关的业务逻辑代码。

Service(领域服务):它存放领域服务代码。一个领域服务是多个实体组合出来的一段业务逻辑。你可以将聚合内所有领域服务都放在一个领域服务类中,你也可以把每一个领域服务设计为一个类。如果领域服务内的业务逻辑相对复杂,我建议你将一个领域服务设计为一个领域服务类,避免由于所有领域服务代码都放在一个领域服务类中,而出现代码臃肿的问题。领域服务封装多个实体或方法后向上层提供应用服务调用。

Repository(仓储):它存放所在聚合的查询或持久化领域对象的代码,通常包括仓储接口和仓储实现方法。为了方便聚合的拆分和组合,我们设定了一个原则:一个聚合对应一个仓储。

特别说明:按照DDD分层架构,仓库实现本应该属于基础层代码,但为了在微服务架构演进时,保证代码拆分和重组的便利性,我是把聚合仓储实现的代码放到了聚合包内,这样,如果需求或者合计发生变化导致聚合需要拆分或重组时,我们就可以将包含核心业务逻辑和仓储代码的聚合包整体迁移,轻松实现微服务架构演进

基础层

Infrastructure 的代码目录结构有:config 和 util 两个子目录。

img

Config:主要存放配置相关代码。

Util:主要存放平台、开发框架、消息、数据库、缓存、文件、总线、网关、第三方类库、通用算法等基础代码,你可以为不同的资源类别建立不同的子目录。

img

在严格分层架构模式下,不允许服务的跨层调用,每个服务只能调用它的下一层服务。服务从下到上依次为:实体方法、领域服务和应用服务。如果需要实现服务的跨层调用,我们应该怎么办?我建议你采用服务逐层封装的方式。

img

img

img

img

目录结构例子

│
│    ├─interface   用户接口层 
│    │    └─controller    控制器,对外提供(Restful)接口
│    │    └─facade      外观模式,对外提供本地接口和dubbo接口
│    │    └─mq          mq消息,消费者消费外部mq消息
│    │ 
│    ├─application 应用层
│    │    ├─assembler     装配器
│    │    ├─dto           数据传输对象,xxxCommand/xxxQuery/xxxVo     
│    │    │    ├─command  接受增删改的参数
│    │    │    ├─query    接受查询的参数
│    │    │    ├─vo       返回给前端的vo对象
│    │    ├─service       应用服务,负责领域的组合、编排、转发、转换和传递
│    │    ├─repository    查询数据的仓库接口
│    │    ├─listener      事件监听定义
│    │ 
│    ├─domain      领域层
│    │    ├─entity        领域实体
│    │    ├─valueobject   领域值对象
│    │    ├─service       领域服务
│    │    ├─repository    仓库接口,增删改的接口
│    │    ├─acl           防腐层接口
│    │    ├─event         领域事件
│    │ 
│    ├─infrastructure  基础设施层
│    │    ├─converter     实体转换器
│    │    ├─repository    仓库
│    │    │    ├─impl     仓库实现
│    │    │    ├─mapper   mybatis mapper接口
│    │    │    ├─po       数据库orm数据对象 
│    │    ├─ack        实体转换器
│    │    ├─mq            mq消息
│    │    ├─cache         缓存
│    │    ├─util          工具类
│    │    
│    

数据对象视图

数据持久化对象 PO(Persistent Object):持久化对象,它跟持久层(通常是关系型数据库)的数据结构形成一一对应的映射关系,如果持久层是关系型数据库,那么,数据表中的每个字段(或若干个)就对应 PO 的一个(或若干个)属性。最形象的理解就是一个 PO 就是数据库中的一条记录,好处是可以把一条记录作为一个对象处理,可以方便的转为其它对象。也有团队使用DO(Data Object)表示数据对象

领域对象 DO(Domain Object):领域对象,就是从现实世界中抽象出来的有形或无形的业务实体,使用的是充血模型设计的对象。也有团队使用用 BO(Business Objects)表示业务对象的概念。

数据传输对象 DTO(Data Transfer Object):数据传输对象,主要用于远程调用之间传输的对象的地方。比如我们一张表有 100 个字段,那么对应的 PO 就有 100 个属性。但是客户端只需要 10 个字段,没有必要把整个 PO 对象传递到客户端,这时我们就可以用只有这 10 个属性的 DTO 来传递结果到客户端,这样也不会暴露服务端表结构。到达客户端以后,如果用这个对象来对应界面显示,那此时它的身份就转为 VO。DTO泛指用于展示层与服务层之间的数据传输对象,当然VO也相当于数据DTO的一种。

视图对象 VO(View Object):视图对象,主要对应界面显示的数据对象。对于一个WEB页面,小程序,微信公众号等前端需要的数据对象。也有团队用VO表示领域层中的Value Object值对象,这个要根据团队的规范来定义。

简单对象POJO(Plain Ordinary Java Object):简单对象,是只具有setter getter方法对象的统称。但是不要把对象名命名成 xxxPOJO!

我们结合下面这张图,看看微服务各层数据对象的职责和转换过程。

img

基础层

基础层的主要对象是po对象。我们需要先建立DO和PO的映射关系。当DO数据需要持久化时,仓储服务会将DO转换为PO对象,完成数据库持久化操作。当DO数据需要初始化时,仓储服务从数据库获取数据对象形成PO对象,并将PO转换为DO,完成数据初始化。大多数情况下PO和DO是一一对应的。但也有DO和PO多对多的情况,在DO和PO数据转换时,需要进行数据重组。

领域层

领域层的主要对象是 DO 对象。DO 是实体和值对象的数据和业务行为载体,承载着基础的核心业务逻辑。通过 DO 和 PO 转换,我们可以完成数据持久化和初始化。

应用层

应用层的主要对象是 DO 对象。如果需要调用其它微服务的应用服务,DO 会转换为DTO,完成跨微服务的数据组装和传输。用户接口层先完成 DTO 到 DO 的转换,然后应用服务接收 DO 进行业务处理。如果 DTO 与 DO 是一对多的关系,这时就需要进行 DO数据重组。

用户接口层

用户接口层会完成 DO 和 DTO 的互转,完成微服务与前端应用数据交互及转换。Facade服务会对多个 DO 对象进行组装,转换为 DTO 对象,向前端应用完成数据转换和传输。

前端应用

前端应用主要是 VO 对象。展现层使用 VO 进行界面展示,通过用户接口层与应用层采用DTO 对象进行数据交互。

总结

DDD 基于各种考虑,有很多的设计原则,也用到了很多的设计模式。条条框框多了,很多人可能就会被束缚住,总是担心或犹豫这是不是原汁原味的 DDD。其实我们不必追求极致的 DDD,这样做反而会导致过度设计,增加开发复杂度和项目成本。DDD 的设计原则或模式,是考虑了很多具体场景或者前提的。有的是为了解耦,如仓储服务、边界以及分层,有的则是为了保证数据一致性,如聚合根管理等。在理解了这些设计原则的根本原因后,有些场景你就可以灵活把握设计方法了,你可以突破一些原则,不必受限于条条框框,大胆选择最合适的方法。

### 回答1: 好的。DDD数据领域模型项目的目录结构通常包括以下几个部分: - 应用层(Application Layer):这一层包含了对领域对象的操作的具体实现。通常包括命令(Command)、查询(Query)、服务(Service)和工厂(Factory)等。 - 领域层(Domain Layer):这一层包含了领域对象的定义,以及这些对象之间的关系。通常包括实体(Entity)、值对象(Value Object)、领域事件(Domain Event)和领域服务(Domain Service)等。 - 基础设施层(Infrastructure Layer):这一层包含了支持应用的各种基础设施。通常包括数据访问层(Data Access Layer)、消息传递层(Messaging Layer)、身份认证和授权层(Identity and Access Control Layer)等。 - 其他部分:通常还包括测试(Test)、文档(Documentation)等。 注意,上述结构只是一种比较常见的架构,并不是所有的DDD项目都必须遵循这种结构。 ### 回答2: DDD(领域驱动设计)是一种软件开发方法,它通过将业务领域模型作为核心来推动软件设计的高内聚性和低耦合性。在DDD中,项目目录结构的设计是至关重要的,它决定了开发人员在工作时的组织和查找代码的方式。 DDD项目目录通常包括以下几个主要部分: 1. 领域模型层:这是实现业务领域模型的核心部分。它包含了领域实体(Entities)、值对象(Value Objects)、聚合根(Aggregate Roots)等等。在该层中,应该按照聚合来组织代码,每个聚合都应该有一个独立的文件夹用于存放与之相关的代码。 2. 应用层:这是应用程序与领域模型之间的桥梁。它包含了应用服务(Application Services)以及与领域模型的交互逻辑。在该层中,可以按照业务功能或者用例来组织代码,每个用例都应该有一个对应的文件夹。 3. 基础设施层:这是与外部系统交互的部分。它包含了与数据库、消息队列、外部API等等的交互代码。在该层中,可以按照技术组件来组织代码,每个技术组件都应该有一个独立的文件夹。 4. 用户界面层:这是应用程序的展示层。它包含了与用户交互的代码,如前端界面、用户输入验证等等。在该层中,可以按照用户界面组件来组织代码,每个组件都应该有一个独立的文件夹。 此外,还可以在项目目录中加入一些公共模块,如异常处理、日志记录等等。这些模块应该被所有其他层使用,并在整个项目中保持一致。 在实际开发中,可以根据项目的规模和复杂性适当调整目录结构。重要的是要保持一致性和可维护性,让开发人员能够快速定位代码,并且易于扩展和修改。同时,良好的项目目录结构也有助于交流合作,提高团队开发效率。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值