如何领域驱动设计?

主要是在开发过程中,个人对于领域驱动设计的实践感悟和总结;也是对新进开发人员的培训资料;希望对关注DDD的童鞋有所帮助。 概述 领域驱动不是纯粹的技术问题,领

主要是在开发过程中,个人对于领域驱动设计的实践感悟和总结;也是对新进开发人员的培训资料;希望对关注DDD的童鞋有所帮助。

概述

领域驱动不是纯粹的技术问题,领域建模(建立数据表只是一部分)是领域专家(客户/产品团队)和开发人员沟通努力、抽象的的结果。

领域建模的目的是,经过有效的沟通、详细分析、 良好设计可以更好的适应未来的变化。

领域驱动设计的核心是建立正确的领域模型。

面向人员

后端开发人员、产品人员

一、背景

  1. 领域驱动设计是什么?

    领域驱动设计的核心是建立正确的领域模型,正确的反应业务,并适应变化。

  2. 为什么建立一个领域模型是重要的

    (1). 领域模型是具有边界的领域抽象,反映了领域业务需求的本质,边界指只领域内所关注的部分;

    (2). 领域模型只反映业务,和任何技术实现无关, 包括实体概念(如商品)和过程概念(资金转账);

    (3).领域模型确保业务逻辑内聚在一个模型中,帮助可理解和重用;

    (4). 领域模型帮助开发人员平滑转换为软件构造;

    (5).领域模型贯穿软件分析设计开发整个过程,领域专家、设计、开发人员始终保持沟通,共享信息,确保软件真正满足需求;

    (6).建立正确的领域模型并不简单,需要领域专家、设计、开发人员积极沟通共同努力,然后才能使大家对领域(业务需求)的认识不断深入,从而不断细化和完善领域模型;

    (7).领域模型是整个软件的核心,是最有价值和最具竞争力的部分;设计足够精良且符合业务需求的领域模型能够更快速的响应需求变化;

  3. 领域建模时思考问题的角度

二、概念

领域驱动分层

领域驱动分层结构

User Interface 用户界面层

在PC页面、APP界面、WebAPI接口展示数据;

发送命令给应用层要求其执行某个用户命令;

Application 应用层

定义系统要完成的所有任务,对用户界面层提供应用功能。对内调用领域层(领域对象或领域服务)完成业务逻辑,应用层不包含业务逻辑。

Domain 领域层

负责表达业务概念,业务状态信息以及业务规则,领域模型处于这一层,是业务软件的核心。

限界上下文

限界上下文是个高内聚的领域模型(例订单模块),是未来系统做水平拆分的关键,可以说就是将一个限界上下文模型拆分升级为一个子系统。

开发人员可以简单理解,限界上下文可以转换成代码,放在一个高内聚的dll项目;

AggregateRoot 聚合根

聚合,它通过定义对象之间清晰的所属关系和边界来实现领域模型的内聚,并避免了错综复杂的难以维护的对象关系网的形成。聚合定义了一组具有内聚关系的相关对象的集合,我们把聚合看作是一个修改数据的单元。

聚合的特点:

(1). 每个聚合有一个根和一个边界,边界定义了一个聚合内部有哪些实体或值对象,根是聚合内的某个实体;

(2). 聚合内部的对象之间可以相互引用,但是聚合外部如果要访问聚合内部的对象时,必须通过聚合根开始导航,绝对不能绕过聚合根直接访问聚合内的对象,也就是说聚合根是外部可以保持 对它的引用的唯一元素;

(3). 聚合内除根以外的其他实体的唯一标识都是本地标识,也就是只要在聚合内部保持唯一即可,因为它们总是从属于这个聚合的;

(4). 聚合根负责与外部其他对象打交道并维护自己内部的业务规则;

(5). 基于聚合的以上概念,我们可以推论出从数据库查询时的单元也是以聚合为一个单元,也就是说我们不能直接查询聚合内部的某个非根的对象;

(6). 聚合内部的对象可以保持对其他聚合根的引用;
删除一个聚合根时必须同时删除该聚合内的所有相关对象,因为他们都同属于一个聚合,是一个完整的概念;

如何识别聚合及聚合根?

我觉得我们可以先从业务的角度深入思考,然后慢慢分析出有哪些对象是:
有独立存在的意义,即它是不依赖于其他对象的存在它才有意义的;
可以被独立访问的,还是必须通过某个其他对象导航得到的;

如何识别聚合根?

如果一个聚合只有一个实体,那么这个实体就是聚合根;如果有多个实体,那么我们可以思考聚合内哪个对象有独立存在的意义并且可以和外部直接进行交互。

Entity 实体

不能独立存在的业务对象,必须挂在聚合根上。

ValueObject 值对象

定义:在领域中,不需要唯一键标识的对象,包括:

常见的值对象:

字符串常量;

枚举;

无主键约束的引用对象;

如果有两个Customer的地址信息是一样的,我们就会认为这两个Customer的地址是同一个。也就是说只要地址信息一样,我们就认为是同一个地址Address。

Domain Service 领域服务

领域中的一些概念不太适合建模为对象,即归类到实体对象或值对象,因为它们本质上就是一些操作,一些动作,而不是事物。这些操作或动作往往会涉及到多个领域对象。

领域服务一个很重要的功能就是可以避免领域逻辑泄露到应用层。

Domain Event 领域事件

容易降低耦合,方便做到高扩展性;

领域聚合根之间很难做到强一致性,大多数都是最终一致性;

Infrastructure 基础设施层

本层为其他层提供通用的技术能力;提供了层间的通信;为领域层实现持久化机制;总之,基础设施层可以通过架构和框架来支持其他层的技术需求;

三、案例分析

那些是聚合、聚合根、实体、值对象?

辨别聚合根

注意

开发人员/团队需要和产品团队/客户保持充分的沟通。