欢迎你们关注公众号「JAVA前线」查看更多精彩分享文章,主要包括源码分析、实际应用、架构思惟、职场分享、产品思考等等,同时欢迎你们加我微信「java_front」一块儿交流学习java
领域驱动设计DDD是一段时间以来比较流行的概念,可是在使用时以为概念不少难以落地。本文就来探讨DDD落地时须要关注的六个问题,并经过一个足球运动员信息管理系统案例分析落地的六个步骤。数据库
DDD方法论的核心是将问题不断分解,把大问题分解为小问题,大业务分解小领域,简而言之就是分而治之,各个击破。设计模式
分而治之是指直接面对大业务咱们无从下手,须要按照必定方法进行分解,分解为高内聚的小领域,使得业务有边界清晰,而这些小领域是咱们有能力处理的,这就是领域驱动设计的核心。缓存
各个击破是指当问题被拆分为小领域后,由于小领域业务内聚,其子领域高度相关,咱们在技术维度能够对其进行详细设计,在管理维度能够按照领域对项目进行分工。须要指出DDD不能替代详细设计,DDD是为了更清晰地行详细设计。微信
在微服务流行的互联网行业,当业务逐渐复杂时,技术人员须要解决如何划分微服务边界的问题,DDD这种清晰化业务边界的特性正好能够用来解决这个问题。markdown
咱们的目标是将业务划分清晰的边界,而DDD是达成目标的有效方法之一,这一点是须要格外注意的。DDD是方法不是目标,不须要为了使用而使用。例如业务模型比较简单能够很容易分析的业务就不须要使用DDD,还有一些目标是快速验证类型的项目,追求短平快,前期可能也不须要使用领域驱动设计。数据结构
领域能够划分多个子领域,子域能够再划分多个子子域,限界上下文本质上也是一种子子域,那么在业务分解时一个业务模块究竟是领域、子域仍是子子域?架构
我认为不用纠结在这个问题,由于这取决于看待这个模块的角度。你认为总体多是别人的局部,你认为的局部多是别人的总体,叫什么名字不重要,最重要的是按照高内聚的原则将业务高度相关的模块收敛在一块儿。框架
业务划分粒度的粗细并无统一的标准,仍是要根据业务须要、开发资源、技术实力等因素综合考量。例如微服务拆分过细反而会增长开发、部署和维护的复杂度,可是拆分过粗可能会致使大量业务高度耦合,开发部署起来是挺快的,可是缺失可维护性和可扩展性,这须要根据实际状况作出权衡。dom
领域对象与数据对象一个重要的区别是值对象存储方式。在讨论领域对象和数据对象以前,咱们首先讨论实体和值对象这一组概念。实体是具备惟一标识的对象,而惟一标识会伴随实体对象整个生命周期而且不可变动。值对象本质上是属性的集合,并无惟一标识。
领域对象在包含值对象的同时也保留了值对象的业务含义,而数据对象可使用更加松散的结构保存值对象,简化数据库设计。
如今假设咱们须要管理足球运动员信息,对应的领域模型和数据模型应该如何设计?姓名、身高、体重是一名运动员本质属性,加上惟一编号能够对应实体对象。跑动距离,传球成功率,进球数是运动员比赛中的表现,这些属性的集合能够对应值对象。
值对象在数据对象中能够用松散的数据结构进行存储,而值对象在领域对象中须要保留其业务含义:
根据图示编写领域对象与数据对象代码:
// 数据对象
public class FootballPlayerDO {
private Long id;
private String name;
private Integer height;
private Integer weight;
private String gamePerformance;
}
// 领域对象
public class FootballPlayerDMO {
private Long id;
private String name;
private Integer height;
private Integer weight;
private GamePerformanceVO gamePerformanceVO;
}
public class GamePerformanceVO {
private Double runDistance;
private Double passSuccess;
private Integer scoreNum;
}
复制代码
抽象的核心是找相同,对不一样事物提取公因式。实现的核心是找不一样,扩展各自的属性和特色。例如模板方法设计模式正是用抽象构建框架,用实现扩展细节。
咱们再回到数据模型的讨论,能够发现脚本化是一种拓展灵活性的方式,脚本化不只指使用groovy、QLExpress脚本加强系统灵活性,还包括松散可扩展的数据结构。数据模型抽象出了姓名、身高、体重这些基本属性,对于频繁变化的比赛表现属性,这些属性值可能常常变化,甚至属性自己也是常常变化,例如可能会加上射门次数,突破次数等,因此采用松散的JSON数据结构进行存储。
工程理论老是要落地的,落地也是须要一些步骤和方法的。本文咱们一块儿分析一个足球运动员信息管理系统,目标是管理运动员从转会到上场比赛整条链路信息,这个系统你们应该也都没有接触过,咱们一块儿来分析。须要说明本实例着重演示DDD方法论如何落地,业务细节可能并不能面面俱到。
梳理流程有两个问题须要考虑,第一个问题是从什么视角去梳理?由于不一样的人看到的流程是不同的。答案是取决于系统须要解决的是什么问题,由于咱们要管理运动员从转会到上场比赛整条链路信息,因此从运动员视角出发是一个合适的选择。
第二个问题是对业务不熟悉怎么办?由于咱们不是体育和运动专家,并不清楚整条链路的业务细节。答案是梳理流程时必定要有业务专家在场,由于没有真实业务细节,没法领域驱动设计。同理在互联网梳理复杂业务流程时,必定要有对相关业务熟悉的产品经理或者运营一块儿参与。
假设足球业务专家梳理出了业务流程,运动员提出转会,协商一致后到新俱乐部体检,体检经过就进行签约。进入新俱乐部后进行训练,训练指标达标后上场比赛,赛后参加新闻发布会。
四色建模第一种颜色是红色,表示时标对象。时标对象是四色建模最重要的对象,能够理解为核心业务单据。在业务进行过程当中必定要对关键业务留下单据,经过这些单据能够追溯出整个业务流程。
时标对象具备两个特色:第一是事实不可变性,记录了过去某个时间点或时间段内发生的事实。第二是责任可追溯性,记录了管理者关注的信息。如今咱们分析本系统时标对象有哪些,须要留下哪些核心业务单据。
转会对应转会单据,体检对应体检单据,签合同对应合同单据,训练对应训练指标单据,比赛对应比赛指标单据,新闻发布会对应采访单据。根据分析绘制以下时标对象:
这三类对象在四色建模中用绿色表示,咱们以电商场景为例进行说明。用户支付购买商家的商品时,用户和商家是参与方。物流系统发货时配送单据须要有配送地址对象,地址对象就是地。订单须要商品对象,物流配送须要有货品,商品和货品就是物。
咱们分析本例获得「参与方」包含总经理、队医、教练、球迷、记者,「地」包括训练地址、比赛地址、采访地址,「物」包含签名球衣和签名足球。
在四色建模中用黄色表示,这类对象表示参与方、地、物是以什么角色参与到业务流程。
增长对象相关描述信息,在四色建模法用蓝色表示。
在四色建模过程当中咱们体会到时标对象是最重要的对象,由于其承载了业务系统核心单据。在划分领域时咱们一样离不开时标对象,核心是经过收敛相关时标对象划分业务领域。
当业务系统发生一件事情时,若是本领域或其它领域有后续动做跟进,那么咱们把这件事情称为领域事件,这个事件须要被感知。
例如球员比赛受伤了,这是比赛子域事件,可是医疗和训练子域是须要感知的,那么比赛子域就发出一个事件,医疗和训练子域会订阅。
例如球员比赛取得进球,这也是比赛子域事件,可是训练和合同子域也会关注这个事件,那么比赛子域也会发出一个事件,训练和合同子域会订阅。
经过事件交互有一个问题须要注意,经过事件订阅实现业务只能采用最终一致性,须要放弃强一致性,这一点可能会引入新的复杂度须要权衡。
接口层:提供面向外部接口声明和DTO对象
访问层:提供HTTP访问入口
业务层:领域层和业务层都包含业务,可是用途不一样。业务层能够组合不一样领域业务,而且能够增长流控、监控、日志、权限控制切面,相较于领域层更为丰富,提供BO对象
领域层:提供DMO(DomainObject)、VO、事件、数据访问对象,核心是按照领域进行分包,领域内高内聚,领域间低耦合
外部访问层:在这个模块中调用外部RPC服务,解析返回码和返回数据
基础层:包含基础功能,例如缓存工具,消息队列,分布式锁,消息发送等功能
咱们展开分析领域层,核心是按照领域进行分包,而且提供DMO、VO、事件、数据访问对象,领域内高内聚,领域间低耦合,例如domain1对应合同子域,domain2对应训练子域。
目前为止领域已经肯定了,如今能够划分任务了,组内成员分别负责一个或多个领域进行详细设计,这个阶段就是你们熟悉的用例图,活动图,时序图,数据库设计,接口设计的用武之地。须要说明领域驱动设计不是取代详细设计,而是为了更清晰地详细设计。
本文探讨了DDD落地时须要关注的六个问题,并经过一个足球运动员信息管理系统案例分析落地的六个步骤。在实际应用中各业务形态可能千差万别,可是方法论却能够通用,咱们须要明确DDD核心是分而治之各个击破,并配合一些通过检验的有效方法进行建模,但愿本文对你们有所帮助。
欢迎你们关注公众号「JAVA前线」查看更多精彩分享文章,主要包括源码分析、实际应用、架构思惟、职场分享、产品思考等等,同时欢迎你们加我微信「java_front」一块儿交流学习