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. 基于flex布局的header

    一.如图 二.思路 1.定义header,设置宽为100%,高为60px,设置绝对定位,使其为漂浮层.在header里添加container,宽设置为版心宽度,并且设置flex布局. 2.在conta ...

  2. FastReport合并多份报表为一份预览打印

    效果 比较简单,直接贴代码 //打印第一份报表 procedure TForm1.Button2Click(Sender: TObject); begin frxReport1.LoadFromFil ...

  3. mybatis整理笔记

    以下是idea2018辑编器 新建 Maven工程 1  file ->new ->project 新建后编程器在右下角加载插件.,这个时候需要会儿,  加载好后,软件目录会多一个ja包 ...

  4. UI自动化测试:App的Webview页面元素左滑

      一.前言 在做App自动化测试时,我们会遇到如上图所示的列表数据页面左滑删除场景,一般可以通过location.rect方法获取对应列表的元素坐标,然后使用TouchAction或者swipe滑动 ...

  5. Django学习day01随堂笔记

    每日测验 """ 每日测验 1.你所知道的前端框架和实用插件有哪些,他们各有什么特点 2.使用bootstrap需要注意什么,常用的bootstrap样式有哪些 &quo ...

  6. JSON,XML设计模式详解

    JSON在Java中的应用: Json概念: json 是一种轻量级的数据交换格式,采用完全独立于编程语言的文本格式用来存储和表示数据.JSON的语言简洁清晰,广为大众所欢迎,是一种理想的数据交换语言 ...

  7. Docker入门系列之二:Docker术语

    原文作者:Jeff Hale 原文地址:https://towardsdatascience.com/learn-enough-docker-to-be-useful-1c40ea269fa8 翻译: ...

  8. Java基础(六)——集合

    一.概述 1.介绍 为什么出现集合? 答:面向对象语言对事物的体现都是以对象的形式,所以为了方便对多个对象的操作,对对象进行存储,集合就是存储对象最常用的一种方式. 数组和集合类同是容器,有何不同? ...

  9. gin 源码阅读(1) - gin 与 net/http 的关系

    gin 是目前 Go 里面使用最广泛的框架之一了,弄清楚 gin 框架的原理,有助于我们更好的使用 gin. 这个系列 gin 源码阅读会逐步讲明白 gin 的原理. gin 概览 想弄清楚 gin, ...

  10. cmake入门:01 构建一个简单的可执行程序

    一.目录结构 CMakeLists.txt:cmake 工程入口文件,包含当前目录下的工程组织信息.cmake 指令根据此文件生成相应的 MakeFile 文件. Hello.c: 源代码文件 bui ...