1. 背景

参考《DDD领域驱动设计-案例需求文档》,本文将构建实体,聚合根详述领域驱动中的建模设计。构建实体,聚合根的一些原则或方法,将在后续文章中说明。

2. 建模设计

2.1. 实体建模

参考售后补偿需求文档,对售后补偿业务做领域建模。现规划如下:

2.1.1. 补偿单聚合跟

补偿单聚合根主要是针对业务中,用户通过不同的场景创建补偿单的过程。如售后管理人员,客服人员通过后端管理系统发起补偿申请,电商用户通过app发起售后补偿申请。补偿单聚合根具有申请,修改状态,修改补偿信息等行为,整个过程在领域层做业务实现,最终通过仓库层落地到数据库。补偿聚合根的唯一标识为补偿单号,该补偿单号最终会落地到数据表中。补偿单聚合根具体组成属性如下图(右键图片,在新标签页中查看,可查看完整大图):
2.1.1.1. 补偿单实体
本例中的补偿单实体就是补偿单聚合根。他包括补偿单基础信息和补偿单方案信息。这里的补偿单基础信息和补偿单方案类似于订单信息和订单明细的关系,即一个为整体一个为部分。整体与部分具有共同的生命周期。部分依赖于整体,所以补偿方案与补偿单是一种组合的关系。
2.1.1.2. 补偿策略实体
补偿策略依赖于补偿单,抛开具体的补偿单,单独的补偿策略在系统中是不能独立存在的。补偿策略设置为一个实体,它是补偿单聚合根的一部分。补偿策略实体不能与补偿单实体分开,这两个实体中,补偿策略的信息,又会影响到补偿单实体的信息,如补偿策略为商品退款模式,补偿商品的总金额也要记录到补偿单实体的信息中。
一个策略实体由具体的补偿方案组成,分别为商品补偿策略实体,补发补偿策略实体,非商品补偿策略值对象三个方案中的一个方案组成(有且仅有一个)。因此策略实体于具体的子策略方案是一种聚合的关系。
2.1.1.3. 商品退款子实体
售后原因为商品原因导致的,针对这样的情况,为客服做补偿处理(不补发商品,可通过其他补偿如红包,代金卷),一个补偿单是基于订单的,一个订单存在多个商品的情况,因此一个补偿单存在多个商品需要补偿的情况。
2.1.1.4. 补发补偿子实体
最终对用户的补偿方案为补发商品。补发商品存在补发多个商品的情况。(补发与非补发,业务场景不同,需要的参数不同,是两个独立的实体)。
2.1.1.5. 非商品特殊补偿值对象
补偿的原因不是商品导致的,其他原因直接做的商品补偿。不补发商品,可通过其他补偿如红包,代金卷等放松补偿。

2.1.2. 售后履约单聚合根

售后履约单是售后补偿单的下游单据,当补偿单审批通过后,就开始真正执行补偿履约的功能了。补偿处理过程较长,有自己的生命周期,与补偿单的生命周期不一样,设置售后履约单聚合根,便于维护补偿过程中的信息。一个履约单在处理过程中,可能异步接收下级系统反馈的信息,将下级系统反馈的信息设置为履约单的值对象信息。履约单聚合根具体组成属性如下图(右键图片,在新标签页中查看,可查看完整大图):
2.1.2.1. 创建订单反馈值对象
补偿处理模式为补发时,会调用订单系统创建订单,订单系统又会基于消息通知售后补偿系统订单出库了。建立订单反馈值对象,用于接收订单创建成功时的消息。
2.1.2.2. 创建退款反馈值对象
补偿处理模式为商品补偿时,会调用支付系统发起退款,支付系统又会基于消息通知售后补偿系统退款的结果。建立退款反馈值对象,用于接收退款处理的消息。

2.2. 领域服务

实体行为的具体逻辑实现,单独编写一个实现类,这种类在DDD里被叫做领域服务(Domain Service)。

2.2.1. 补偿单聚合根领域服务设计

售后补偿单聚合根中,对于行为中简单的逻辑,如修改责任方信息,设置单据终止等直接在领域服务中编写实现逻辑代码。对于存在多个分支,复杂的情况如审批,保存,应基于面向对象编程思维,采用接口的模式完成功能。
例如:补偿聚合根保存时,补偿方案不同,保存的数据不同,判断的逻辑不同,应该将补偿策略信息单独抽象出来,在领域服务中,完善补偿策略信息。可根据策略设计模式,把可能导致分支变化的模块独立出来,基于接口编程,便于后续功能扩展和维护。
补偿单聚合根领域服务实现类图参考如下(右键图片,在新标签页中查看,可查看完整大图):

2.2.2. 履约单聚合根领域服务设计

补偿履约单是补偿单的下级单据,当补偿单据审批通过后,就创建补偿履约单。补偿履约单有自己的行为和生命周期。
补偿履约单处理过程中,失败时,仅修改履约单的单据状态,补偿完成时,也只修改履约单的单据状态。(不可在补偿履约聚合根中,直接操作补偿单聚合根修改补偿单的状态)。
售后补偿处理:调用售后履约单聚合根的处理行为,处理结果分为三种:
  1. 处理通过:这种是履约单调用下级系统,可以同步得到处理结果(成功或失败)。
  2. 处理中:履约单调用下级系统,是一个异步的回复过程。只有等下级单反馈后,才可以做补偿完成。处理中状态,设置履约单状态为处理中。
  3. 处理异常:履约单处理过程发生异常,记录补偿履约待沟通记录。
补偿处理场景举例如:
  • 履约单处理为补发订单时,发起处理并不能马上得到处理的结果。针对这样的情况,为履约单设计一个接受下级反馈的行为。
  • 履约单处理为其他模式补偿处理时,发起处理可以同步得到处理结果。基于接口编程,顶级接口设置了接受下级反馈函数(设置一个默认的default方法),实现类可不实现下级反馈函数。
履约单聚合根领域服务实现类图参考如下(右键图片,在新标签页中查看,可查看完整大图):

2.3. 事件通知

当履约单结束时,仅仅表示补偿单的履约环节结束了,并不表示整个补偿单完结了。补偿单与履约单是两个实体,不能跨越实体,直接在履约单中调用补偿单的完成行为。同时,履约单完成了,也不需要马上要求补偿单就完成,因此履约单完成后,可发送一个完成事件通知。
补偿完成存在两种情况:
  1. 补偿履约单在发起处理时,同步就完成了。
  2. 补偿履约单发起处理后,由下级系统反馈,异步告知补偿完成。
履约处理后,只更新履约单的状态。发布一个履约单事件,通知其他实体做对应的业务处理。参考事件通知的模式,基于Spring Event事件通知机制,做履约单后续的副作用业务处理(未采用领域事件模式,该模式还存在不完善的地方,采用Spring Event稳定可靠)。
履约单完成后,发送事件,补偿单监听事件,做后续业务处理:
  1. 当通知信息为履约单处理异常,补偿单变更为待沟通状态;
  2. 当通知信息为履约单处理成功,补偿单变更为结束状态;
  3. 当通知信息为履约单处理中时,补偿单变更为补偿中状态;

DDD领域驱动设计-案例建模设计-Ⅲ的更多相关文章

  1. DDD 领域驱动设计-商品建模之路

    最近在做电商业务中,有关商品业务改版的一些东西,后端的架构设计采用现在很流行的微服务,有关微服务的简单概念: 微服务是一种架构风格,一个大型复杂软件应用由一个或多个微服务组成.系统中的各个微服务可被独 ...

  2. C#进阶系列——DDD领域驱动设计初探(一):聚合

    前言:又有差不多半个月没写点什么了,感觉这样很对不起自己似的.今天看到一篇博文里面写道:越是忙人越有时间写博客.呵呵,似乎有点道理,博主为了证明自己也是忙人,这不就来学习下DDD这么一个听上去高大上的 ...

  3. DDD领域驱动设计和实践(转载)

    -->目录导航 一. DDD领域驱动设计介绍 1. 什么是领域驱动设计(DDD) 2. 领域驱动设计的特点 3. 如果不使用DDD? 4. 领域驱动设计的分层架构和构成要素 5. 事务脚本和领域 ...

  4. DDD领域驱动设计初探

    DDD领域驱动设计初探1 前言:又有差不多半个月没写点什么了,感觉这样很对不起自己似的.今天看到一篇博文里面写道:越是忙人越有时间写博客.呵呵,似乎有点道理,博主为了证明自己也是忙人,这不就来学习下D ...

  5. DDD领域驱动设计初探(一):聚合

    前言:又有差不多半个月没写点什么了,感觉这样很对不起自己似的.今天看到一篇博文里面写道:越是忙人越有时间写博客.呵呵,似乎有点道理,博主为了证明自己也是忙人,这不就来学习下DDD这么一个听上去高大上的 ...

  6. DDD领域驱动设计-概述-Ⅰ

     如果我看得更远,那是因为我站在巨人的肩膀上.(If I have seen further it is by standing on ye shoulder of Giants.)         ...

  7. DDD领域驱动设计-设计规范-Ⅵ

    不以规矩,不能成方圆.                                                                     -战国·邹·孟轲<孟子·离娄章句上 ...

  8. 浅谈我对DDD领域驱动设计的理解

    从遇到问题开始 当人们要做一个软件系统时,一般总是因为遇到了什么问题,然后希望通过一个软件系统来解决. 比如,我是一家企业,然后我觉得我现在线下销售自己的产品还不够,我希望能够在线上也能销售自己的产品 ...

  9. DDD领域驱动设计之聚合、实体、值对象

    关于具体需求,请看前面的博文:DDD领域驱动设计实践篇之如何提取模型,下面是具体的实体.聚合.值对象的代码,不想多说什么是实体.聚合等概念,相信理论的东西大家已经知晓了.本人对DDD表示好奇,没有在真 ...

随机推荐

  1. 计算机网络参考模型和5G模型的那些事

    一.分层思想 二.OSI参考模型 三.TCP/IP协议族 四.数据封装和解封装过程 五.层间通讯过程 六.3GPP规范及5G协议栈 一.分层思想 享用牛奶的人未必了解其生产过程 使用网络的人未必知道数 ...

  2. js根据日期获取所在周

    一.获取时间所在周的周一.周五 function getFirstLastDay (time) { let date = new Date(time) let Time = date.getTime( ...

  3. Java基础系列(5)- 使用IDEA开发

    IDEA开发 下载安装IDEA https://www.cnblogs.com/gltou/p/14956060.html 使用IDEA编写helloworld 踩坑总结 run的时候提示" ...

  4. Dapr + .NET Core实战(四)发布和订阅

    什么是发布-订阅 发布订阅是一种众所周知并被广泛使用的消息传送模式,常用在微服务架构的服务间通信,高并发削峰等情况.但是不同的消息中间件之间存在细微的差异,项目使用不同的产品需要实现不同的实现类,虽然 ...

  5. Jmeter线程组设置

    添加线程组:右键测试计划->添加->Threads->线程组 左侧树形标签栏中,显示标签信息. 选中线程组,右侧内容栏中显示线程组的相关信息. 名称:可以给线程组设置一个个性化的命名 ...

  6. docker 入门(docker 镜像 、容器、仓库)

    一.关于docker 镜像 .容器.仓库之间的关系 镜像(Image): 类似于虚拟机 的镜像 容器(Container): 类似于操作系统(或者说是独立的软件), 由镜像可以创建大量的容器. 仓库( ...

  7. pytest环境准备与入门

    前言pytest 是 python2 默认自带的,python3 的版本 pytest 框架独立出来了,需用 pip 安装.以下为 python3.7版本为例 pytest是python的一种单元测试 ...

  8. Spring,AOP实现功能级别权限验证

    1. 首先是问题出现的原因 对于一个我的一个个人博客网站,我希望游客可以浏览我的博客,但是评论功能是需要登录才能使用 这就需要对某个功能进行权限验证 对于过滤器,拦截器,AOP的区别日后再讨论,现在是 ...

  9. 数据库建表权限 CREATE command denied to user for table

    今天在表中用Navicat连接服务器上的mysql账号进行建表,报了个这样类似的错, CREATE command denied to user for table 是数据库权限设置的问题,所以无法进 ...

  10. 11.2.0.4 ORA-15025 ORA-27041 IBM AIX RISC System/6000 Error: 13: Permission denied

    ASM device error ORA-27041 ORA-15025 ORA-15081 (Doc ID 1487475.1) 描述总结:数据库的alert中发现大量ORA-27041 ORA-1 ...