• DDD领域驱动的核心概念


    概述

    领域的范围关系

    领域包含限界上下文,限界上下文包含子域,子域包含聚合,聚合包含实体和值对象。
    领域-》限界上下文-》子域(微服务)-》聚合-》实体+值对象。

    DDD分层架构

    用户接口层

    用户接口层是前端应用于微服务应用层的桥梁,需要完成DTO到BO、Entity等对象之间的转换。
    这里明确了用户接口层的逻辑十分简单,就是一个接收器、转发器,接收用户的请求,简单的CRUD转发到DomainService中,复杂的业务请求转发到Application中。

    应用服务层

    强调跨聚合服务、跨模块间服务的编排。
    一个聚合的应用服务可以建立一个应用服务类,管理聚合所有的应用服务。
    由于领域核心逻辑已经很好的沉淀到了领域层中,领域层的这些核心逻辑可以高度复用。应用服务只需要灵活的组合和编排这些不同聚合的领域服务就可以很容易的适配前端业务的变化。因此应用层不会积累太多的业务逻辑代码,所以会变的很薄,代码维护起来也会非常容易。

    领域层

    基础层

    对象的分层和转换

    DTO、BO、Entity、VO对象说明。

    • DTO:用在用户接口层,接收、响应用户请求。
    • BO:聚合根(业务对象模型),用在domain层、application层,表达业务涉及思想,抽象业务模型;本身会聚合多个Entity、VO对象。
    • Entity:数据表映射对象,用在domain层、application层,用于表示数据表的模型。
    • VO:值对象,用在domain层、application层,是对Entity对象的补充,用于值传递,和Entity对象一起服务于BO,方便业务模型的表达。
      用户接口层通过DTO接收、响应用户,同时使用assembler装配转换成Entity/BO对象到application或者领域层。
      Entity对象和BO对象之间的转换,转换可以放在domain的factory层也可以放在Entity或者BO对象上。

    聚合相关概念

    聚合的管理

    包括聚合根、实体和值对象的关系。
    实践中聚合根使用xxBO,实体使用xxxEntity,值对象使用xxxVO;
    BO与Entity不是完全的充血模型(只实现简单的本实体内的行为),涉及的到数据库交互,复杂的跨多实体的业务逻辑是放到DomainService中的;
    service原则上只处理本聚合内的业务(符合高内聚低耦合的原则),多聚合服务的编排放在application层中。

    聚合数据的初始化和持久化

    按照DDD的建议是通过仓储模式,domain中实现repository的接口,infrastructure中实现数据库的持久化,符合依赖导致原则。
    但是实践中发现这样虽然解耦了,但是流程太繁琐,通常的微服务持久化只有一种或者两种方式, 没必要使用这么繁琐的流程。
    实践中采用service中调用infrastructure中的mapper接口直接完成数据的持久化,简洁明了。

    聚合的解耦

    聚合的解耦主要体现在跨聚合的服务调用上,三层架构是service直接调用其他聚合的服务,这里我们建议放在application层进行聚合间微服务编排,主要目标是为了方便后期不同的聚合拆分成多个微服务是代码容易拆分。

    领域服务

    领域服务、聚合根、实体提供的服务尽量原子化,这样应用层编排起来比较方便,也不会出现很多容易代码。
    一个聚合可以设计一个领域服务类,管理聚合内索引的领域服务。
    如果一个业务行为由多个实体对象参与完成,就将这部分业务逻辑放在领域服务中,可以理解为领域服务是对聚合内不同实体服务的编排。
    领域服务与实体方法的区别是:

    • 实体方法完成单一实体自身的业务逻辑,是相对简单的原子业务逻辑;
    • 领域服务则是多个实体组合出的相对复杂的业务逻辑。
      注意事项:
      在领域服务或实体方法中,我们尽量避免调用其他聚合的领域服务或引用其他聚合的实体或值对象,这种操作会增加聚合的耦合度。在微服务架构演进时,如果出现聚合拆分和重组,这种跨聚合的服务调用和对象调用,会变成跨微服务的操作,导致这种跨聚合的领域服务调用和对象引用失效,在聚合拆分是会增加代码解耦和重构的工作量。

    领域事件

    事件实体
    通常我们可以把实体拆分成基类Event和领域Event。
    事件的执行逻辑
    1.执行业务逻辑;
    2.完成业务数据持久化;
    3.完成事件数据持久化(可选);
    这一步可选的原因是,如果后期不需要进行对账、重发等确认操作可以无需事件记录持久化。
    4.完成领域事件发布;

    工厂模式

    对于大型的复杂领域模型,聚合内的聚合根、实体、值对象直接的依赖关系比较复杂,这种过于复杂的依赖关系,不适合通过根实体构造器来创建。为了协调这种复杂的领域对象的创建和生命周期管理,在DDD里引入了工厂模式,在工厂里封装复杂的对象创建过程。

    解耦

    由于架构的演进,微服务与生俱来就需要考虑聚合的未来重组。因此微服务的设计和开发要做到未雨绸缪,而这最关键的就是解耦。
    聚合于聚合的解耦
    当多个聚合在同一个微服务时,很多传统架构开发人员会下意识地引用其他聚合的实体和值对象,或者调用其它聚合的领域服务。因为这些聚合的代码在同一个微服务内,运行时不会有问题,开发效率似乎也更高,但这样会不自觉地增加聚合之间的耦合。在微服务架构演进时,如果聚合被分别拆分到不同的微服务中,原来微服务内的关系就会变成跨微服务的关系,原来微服务内的对象引用或服务调用将会失效。最终你还是免不了要花大量的精力去做聚合解耦。虽然前期领域建模和边界划分得很好,但可能会因为开发稍不注意,而导致解耦工作前功尽弃。
    微服务内各层的解耦
    微服务内有四层,在应用层和领域层组成核心业务领域的两端,有个缓冲区或数据转换区。前端与应用层通过组装器实现 DTO 和 BO、Entity的转换,这种适配方式可以更容易地响应前端需求的变化,隐藏核心业务逻辑的实现,保证核心业务逻辑的稳定,实现核心业务逻辑与前端应用的解耦。

    总结

    DDD是一套方法论,目的是为了方便我们业务建模,代码解耦,不要被其中的相关概念束缚住。

  • 相关阅读:
    【深入理解C++】局部变量及初始化
    企业内容建站系统 ModStartCMS v4.5.0 后台登录改版,登录安全增强
    单商户商城系统功能拆解27—营销中心—拼团活动
    基于Java的斗地主游戏案例开发(做牌、洗牌、发牌、看牌
    [Servlet/Tomcat] HttpServletRequest#getHeader(headerNameWithIgnoreCase)(获取header时不区分大小写)
    30岁之前一定要明白的道理
    buuctf crypto 【[GUET-CTF2019]BabyRSA】解题记录
    划重点!CISA、FBI、NSA联合发布深度伪造威胁网络安全报告
    vue uniapp 实现点击获取坐标出现gif
    深度解析Shopee虾皮高效选品逻辑方法
  • 原文地址:https://blog.csdn.net/tianzhonghaoqing/article/details/138189877