• 领域驱动设计2编码规范


    基于DDD领域驱动设计的思想,在开发具体系统时,需要先建立不同的层级包。主要是梳理不同层面(应用层,领域层,基础设施层,展示层)包括的功能目录。

    分层

    1:展示层

    展现层(用户接口层):负责接受Web请求,然后将请求路由给Application层执行,并返回结果,其载体通常是DTO(Data Transfer Object)。

    展示层有两个任务:

    1):从用户处接收命令操作,改变底层系统状态。
    2):从用户处接收查询操作,将底层系统状态以合适的形式呈现给用户。

    项目目录

    1)命令目录(command): 对象命名为XxxCommand,指调用方明确想让系统操作的指令,其预期是对一个系统有影响,也就是写操作。通常来讲指令需要有一个明确的返回值(如同步的操作结果,或异步的指令已经被接受)。

    2)查询目录(query): 对象命名为XxxQuery,指调用方明确想查询的东西,包括查询参数、过滤、分页等条件,其预期是对一个系统的数据完全不影响的,也就是只读操作。

    3)事件目录(event): 对象命名为XxxEvent,指一件已经发生过的既有事实,需要系统根据这个事实作出改变或者响应的,通常事件处理都会有一定的写操作。事件处理器不会有返回值。这里的Event更多是外部一种通知机制而已。

    4)控制层(Controller): 提供restful接口,供外部系统调用

    5)转换(assembler):实体(Entity)转变为 DTO的方法,基于org.mapstruct.Mapper实现

    规范

    ApplicationService的接口入参只能是一个Command、Query或Event对象,CQE对象需要能代表当前方法的语意。唯一可以的例外是根据单一ID查询的情况,可以省略掉一个Query对象的创建

    CQE,DTO,都是Value Object,但是从语义上来看有比较大的差异,主要是从命名上区别出来。

    1):CQE:CQE对象是ApplicationService的输入,是有明确的“意图”的,所以这个对象必须保证其"正确性"。为验证部分字段的格式,必填性,可基于Spring Validation等模式做基础数据验证。
    2):DTO:Dto对象只是数据容器,只是为了和外部交互,所以本身不包含任何逻辑,只是贫血对象。

    2:应用层

    主要负责获取输入,组装上下文,做输入校验,调用领域层做业务处理,如果需要的话,发送消息通知。当然,层次是开放的,若有需要,应用层也可以直接访问基础实施层。相对于领域层,应用层是很薄的一层,应用层定义了软件要完成的任务,要尽量简单.它不包含任务业务规则或知识, 为下一层的领域对象协助任务、委托工作。 

    对外:为展现层提供各种应用功能(service)。

    对内:调用领域层(领域对象或领域服务)完成各种业务逻辑任务

    项目目录

    事件(event): 对象命名为XxxEvent,跨聚合根,或部分业务处理完成后,需要通知其他模块的,本例采用 Spring event模式

    应用服务(service): 对象命名为XxxService,应用层的服务

    规范

    一个应用层通常包括以下三种服务:

    1)业务处理类:XxxCommandService
    2)业务查询类:XxxQueryService
    3)业务事件类:XxxEventService

    3:领域层

    主要是封装了核心业务逻辑,并通过领域服务(Domain Service)和领域对象(Entities)的函数对外部提供业务逻辑的计算和处理。

    领域层主要负责表达业务概念,业务状态信息和业务规则。是一个纯内存化的操作。Domain层是整个系统的核心层,几乎全部的业务逻辑会在该层实现。领域层不关注数据是如何落地存储的,领域层也不直接调用底层仓库接口保存数据,但是可以进行查询操作。

    项目目录

    规范

    1)实体(entity): 对象命名为XxxE,具有唯一标识的对象,所有实体统一用E作为后缀,如PersonE

    2)工厂(factory): 接口命名规则为XxxFactory,创建复杂的实体,聚合根,只做创建处理

    3)值对象(vo): 对象命名为XxxV,无需唯一标识的对象,所有值对像统一同V作为后缀 ,如PersonV,实体的主键编码以Id结尾

    4)领域服务(service): 接口命名规则为XxxDomainService,一些行为无法归类到实体对象或值对象上,本质是一些操作,而非事物(与本例中domain/service包下的含义不同)

    5)仓储(repository): 接口命名规则为XxxRepository,创建复杂对象,隐藏创建细节,提供查找和持久化对象的方法,领域层仅编写仓库的接口,接口实现放在基础层

    6)聚合/聚合根(aggregates,aggregate roots): 对象命名为XxxA,聚合是指一组具有内聚关系的相关对象的集合,每个聚合都有一个root和boundary,所有聚合统一用A作为后缀,如PersonA

     

    4:基础层

    屏蔽数据存储细节,这些数据来源可以是数据库(MySQL,NoSql)、搜索引擎、文件系统、也可以是其他微服务等。向其他层提供 通用的 技术能力(比如工具类,第三方库类支持,常用基本配置,数据访问底层实现,基础实施层主要包含以下的内容:

    1)为应用层 传递消息(比如通知)
    2)为应用层 提供持久化机制(最底层的实现)

    项目目录

    1)防腐层(acl): 实体对接外部系统,实体与外部系统之间,不同领域之间,不同的参数转换,语义转换等

    2)转换层(assembler): 数据转换工具类,如DO(Data Object)转换为实体,实体转换为数据表(DO)对象,基于org.mapstruct.Mapper实现

    3)仓库层(repository): 仓库实现层,实体与DB之间存储的功能层

    4)异常管理(exception): 封装具体业务的异常处理信息

    5)配置模块(config): 封装配置信息,包括一些基础静态字段,基于阿波罗等获取的配置信息

     

    5:其他

    1)实体保存时,仓库层的入参不能为基础的数据表对象,入参对象应设置为实体。
    2)其他命令操作时,应用层调用仓库层保存数据,入参可根据实际的情况传入对应的实体或入参命令对象(比如只是修改数据的个别字段可传入修改命令,修改大量字段信息,传入实体)。
    3)领域层只做纯内存的业务规则操作,原则上不能在领域层中直接调用仓库层存储数据。
    4)应用层的出参设置为DTO或基础数据对象(如主键编码),不能直接返回实体;
    5)当一个业务涉及到多个实体时,不能在一个实体中直接调用另外一个实体(聚合根可调用内部的子实体),应该基于应用层或第三方领域服务协调处理。
    6)明确各个层的职能,不要混用。
    7)领域层做业务规则处理,针对不同的规则场景,建议采用策略设计模式,多用设计模式实现领域服务便于系统后续的扩展和调整。
    8)涉及到主子记录的情况,一般建立聚合根,基于聚合根统一的保存数据。
    9)当业务需要多个实体同时处理时,可在应用层统一加上事务管理。
    10)针对一些基础配置的需求,无业务逻辑,或比较简单的业务(CRUD),采用DDD模式也很费力,此刻不一定非要使用DDD模式。

     
  • 相关阅读:
    appfuse的一些资源
    实战: SOLR的分布式部署(复制)CollectionDistribute 快照分发 (精简版)
    在SOLR环境变量的配置 过程中,遇到的 A pseudo attribute name is expected 异常
    Solr应用开发——Solr home目录结构简介1
    升级 Solr 1.4 后性能有所提升
    Solr 删除数据的几种方式
    如何使SOLR系统自动AUTO COMMIT
    Solr应用开发——Solr home目录结构简介2
    升级到 solr 1.4 的注意事项
    SOLR环境变量的配置
  • 原文地址:https://www.cnblogs.com/at20191018/p/16178101.html
Copyright © 2020-2023  润新知