从这一刻开始,请大家忘记自己是一名技术人员,用业务的角度来思考问题。
1、什么是DDD
DDD(Domain-driven design,领域驱动设计),是一个很好的应用于微服务架构的方法论
DDD要求项目全生命周期中,所有岗位人员都基于业务的角度去思考问题,而不是基于技术角度。
“从理论到实践,再从实践到理论”——杨中科
2、领域(Domain)
领域是指一个组织做的全部事情,可分为不同的子领域,子领域可用归为以下三类:
核心域:解决项目的核心问题,和组织业务密切相关。
支撑域:解决项目的非核心问题,具有组织特性,但不具有通用性。
通用域:解决通用问题,没有组织特性。
领域的不同分类决定了公司的研发重点:
比如:某软件公司,将领域分为
3、领域模型(Domain Model)
用业务的角度,对领域内的元素进行建模,抽象出来的模型图。
比如,银行中有:柜员、客户、ATM、保安、取号机...
识别出这些模型,再用模型描述和构建系统
4、事务脚本
也可称为:伪代码,以易读性为准,用类似代码的语法表达业务需求,如
string WithdrawMoney(string acc,string pwd,double nums) //取钱 { if (!checkUser(acc, pwd)) { return "账户错误"; } double remainingSum = GetRemainingSum(acc); //获取余额 if(remainingSum< nums) { return "余额不足"; } UpdateRemainingSum(remainingSum - nums); //更新余额 return "取款成功"; }
5、通用语音 & 界限上下文
5.1、通用语音:一个拥有确切含义,没有二义性的语音
产生二义性的例子:定义一个对象为"用户",这个用户是指柜员、储户、还是客户经理,没有确切定义,这就是二义性
5.2、界限上下文:通用语音离不开特定的语义环境,只有确定了边界,才能没有歧义的描述一个业务,比如:
1)后台管理系统用户:是指系统管理员、系统流程人员
2)官方网站用户:是指储户、信用卡用户
6、实体(Entity) & 值对象(Value Object)
6.1 实体:可用理解为实体对象,是富有业务行为且具有唯一标识符的对象。在不同的设计阶段实体是可以改变的,但是根据唯一标识符始终能定位到这个唯一对象,如员工(Code:对于员工类)
6.2 值对象:依附于实体存在,如员工居住地址。(Code:对应地址类)
7、聚合(Aggregate) & 聚合根
目的:实现高内聚,低耦合
7.1 聚合:把关系紧密的实体,放到同一个聚合中,如,订单聚合包含:订单、订单明细
7.2 聚合根:每个聚合,都有一个聚合根负责和外部对象进行沟通,如:通过订单访问订单明细
聚合根和聚合内其他实体,体现的是整体和部分的关系,如:订单包含订单明细
聚合的划分没有标准答案,根据业务进行划分。(Code:完善的划分有利于微服务的构建)
聚合内的实体:只有对象创建、初始化、状态管理等个体相关代码,没有业务逻辑代码
订单聚合例子:
订单聚合:订单(根实体)、订单明细(普通实体)
创建订单时,控制订单创建、判断订单数量,属于领域服务
保存订单,属于应用服务
8、领域服务 & 应用服务
8.1 领域服务:针对聚合内业务逻辑,不会和数据库发生直接交互,在简单的业务中领域服务不是必需的(避免过度设计)
8.2 应用服务:针对跨聚合协作、聚合与外部系统协作逻辑(协调多个领域服务、外部系统来完成一个用例)
9、DDD典型用例处理流程
第一步,准备业务操作所需要的数据。
第二步,执行由一个或者多个领域模型做出的业务操作,这些操作会修改实体店状态,或者生成一些操作结果。
第三步,把对实体店改变或者操作结果应用于外部系统。
10、仓储(Repository) & 工作单元(Unit Of Work)
仓储:读取数据/保存对实体的修改
工作单元:聚合内的数据操作紧密相关,若干操作组成一个工作单元;
为保证事务的强一致性,这些操作要么全部成功,要么全部失败(事务)
11、领域事件 & 集成是事件
领域事件:在同一个微服务内的聚合之间的业务传递,使用进程内的通信机制完成。
集成是事件:跨微服务的业务传递,使用事件总线(EventBus)实现
12、贫血模型 & 充血模型
贫血模型:只有属性和成员变量(属性带有get;set;本身并不保存值,值存在生成的隐式私有成员变量中)
充血模型:属性、成员变量、方法
13、EFCore框架实现充血模型的五个要求
1)属性是只读的,或者只能被类内部的代码修改
实现:将属性的set定义为private或者init,然后通过构造方法为属性赋值
2)定义有参构造方法,提供给类实例化
因为EFCore会通过反射直接访问私有属性,实现方式可为:
方式1:构造方法参数名(首字母小写)必须和属性名一致
方式2:保留无参构造函数,定义为private,这是给EFCore从数据库加载数据用的
3)没有定义属性的成员变量也需要映射为数据列,如passWordHash
没有{get;set;}的是成员变量,也叫做字段,正常为private
有{get;set;}的为属性,正常为public,(注意很多时候我们不会定义成员变量,系统会自动生成一个)
实现:builder.Property("成员变量名")
4)有的属性仅从数据库读,而不写
EFCode中提供了支持字段"backing field",来支持这种写法
实现:在配置实体类的代码中,使用builder.Property(e=>e.属性名).HasField("成员变量名")来配置属性为只读
5)有的属性不需要映射到数据列,仅在运行时被使用
实现:使用Ignore()来配置忽略
标签:聚合,何为,实体,业务,领域,订单,DDD,属性 From: https://www.cnblogs.com/wskxy/p/17238474.html