DDD(领域驱动设计)--战术设计
前言
战术设计
战略设计为我们提供一种高层视野来审视我们的软件系统,主要包括领域/子域、通用语言、限界上下文和架构风格等概念,
而战术设计则将战略设计进行具体化和细节化,它主要关注的是技术层面的实施,也是对程序员来得最实在的地方。
战术设计的目的是保证战略的实现。在DDD中,代码就是设计本身,你不再需要那些繁文缛节的并且永远也无法得到实时更新的设计文档。
警惕贫血对象,要创建行为饱满的领域对象并不难,我们需要转变一下思维,将领域对象当做是服务的提供方,而不是数据容器,多思考一个领域对象能够提供哪些行为,而不是数据。
实体
一个实体模型就是一个独立的事物,采用充血模型,具有业务属性和业务行为。每个实体都拥有一个唯一的标识符,可以将它的个性化和所有其他类型相同或者不同的实体区分开。许多时候,实体是可变的,它的状态会随着时间发生变化。
对一个实体进行多次修改,修改后的数据和原来可能会不大相同,但它们依然是同一个实体,因为唯一标识没变。
值对象
一个值对象,是对一个不变的概念整体所建立的模型,没有一个唯一的标识符。在这个模型中,值就真的只有一个值。和实体不一样,它没有唯一标识符,而是由值类型封装的属性对比来决定相等性。此外,一个值对象不是实物,而是常常用来描述、量化或者测量一个实体。
一个典型的值对象是地址值对象,比如下单中,有下单人、商品信息、优惠信息、还有收货地址信息,如果地址信息用省、市、区等属性表示,会有些零碎,拿出来构成一个“地址”属性,会更合适一些,这个多个值的集合就是值对象了。
聚合
在DDD中,实体和值对象是很基础的领域对象,实体跟值对象都只是个体化的对象,它们的行为表现出来的是个体能力。聚合用来确保这些领域对象在实现共同的业务逻辑时,能保证数据的一致性。
聚合是由业务和逻辑紧密关联的实体和值对象组合而成的。聚合是数据修改和持久化的基本单元。
聚合设计的四条基本规则
- 在聚合边界内保护业务规则不变性
- 聚合要设计得小巧
- 只能通过标识符引用其他聚合
- 使用最终一致性更新其他聚合
聚合根
每个聚合都有一个根实体,叫做聚合根,外界只能通过聚合根跟聚合通信。聚合根的主要目的是为了避免由于复杂数据模型缺少统一的业务规则控制,而导致聚合、实体之间数据不一致的问题。
如果把聚合比作一个团队,那么聚合根就是团队的leader,其他团队的需求都需要跟该团队的leader商量后才能开始动工。
领域服务
当某个操作不适合放在聚合和值对象上时,最好的方式便是使用领域服务了。
可以使用领域服务的地方,过度使用领域服务将导致贫血领域模型。
- 执行一个显著的业务操作过程
- 对领域对象进行转换
- 已多个领域对象作为输入进行计算,结果产生一个值对象
领域服务不需要定义接口,直接定义实现即可
- 如果接口有不同的实现,那么需要考虑领域中是否存在特定的功能行为
- 如果我们采用了依赖注入或者工厂,即便接口和实现类是合并在一起的,我们依然能达到这样的目的。依赖倒置容器(例如 Spring)将完成服务实例的注入工作,由于客户端并不负责服务的实例化,它并不知道接口和实现类是分开的还是合并在一起的。
领域服务与实体方法的区别
- 实体方法完成单一实体自身的业务逻辑,相对简单的原子业务逻辑
- 领域服务则是多个实体组合出的相对服务的业务逻辑
仓储
仓储用于保存和获取聚合对象,应该将仓储看作一个对象的集合,而不是数据库的CRUD,更不是一张表一个仓储。
需要做到让用户无感知的,以为就在内存中使用一个集合一样。
仓储的出现就是为了让大家聚焦领域模型,不要聚焦表结构。
领域事件
领域事件是一条记录,记录着在限界上下文中发生的对业务产生重要影响的事情,经常用于保证两个聚合之间的一致性。
对于领域事件的命名,必须体现出模型的通用语言,这些名词是连接模型之间的桥梁,对发生的事情进行充分的沟通至关重要。
领域事件类型名称应该是对过去发生事情的陈述,即动词的过去式,如OrderCreated。
参考资料
- 《领域驱动设计——软件核心复杂性应对之道》
- 《实现领域驱动设计》
- 《领域驱动设计精粹》
DDD(领域驱动设计)--战术设计的更多相关文章
- DDD 领域驱动设计-商品建模之路
最近在做电商业务中,有关商品业务改版的一些东西,后端的架构设计采用现在很流行的微服务,有关微服务的简单概念: 微服务是一种架构风格,一个大型复杂软件应用由一个或多个微服务组成.系统中的各个微服务可被独 ...
- DDD领域驱动设计落地实践(十分钟看完,半小时落地)
一.引子 不知今年吹了什么风,忽然DDD领域驱动设计进入大家视野.该思想源于2003年 Eric Evans编写的"Domain-Driven Design领域驱动设计"简称DDD ...
- 浅谈我对DDD领域驱动设计的理解
从遇到问题开始 当人们要做一个软件系统时,一般总是因为遇到了什么问题,然后希望通过一个软件系统来解决. 比如,我是一家企业,然后我觉得我现在线下销售自己的产品还不够,我希望能够在线上也能销售自己的产品 ...
- DDD 领域驱动设计-谈谈 Repository、IUnitOfWork 和 IDbContext 的实践(3)
上一篇:<DDD 领域驱动设计-谈谈 Repository.IUnitOfWork 和 IDbContext 的实践(2)> 这篇文章主要是对 DDD.Sample 框架增加 Transa ...
- DDD 领域驱动设计-两个实体的碰撞火花
上一篇:<DDD 领域驱动设计-领域模型中的用户设计?> 开源地址:https://github.com/yuezhongxin/CNBlogs.Apply.Sample(代码已更新) 在 ...
- DDD 领域驱动设计-谈谈 Repository、IUnitOfWork 和 IDbContext 的实践(2)
上一篇:<DDD 领域驱动设计-谈谈 Repository.IUnitOfWork 和 IDbContext 的实践(1)> 阅读目录: 抽离 IRepository 并改造 Reposi ...
- DDD 领域驱动设计-领域模型中的用户设计
上一篇:<DDD 领域驱动设计-如何控制业务流程?> 开源地址:https://github.com/yuezhongxin/CNBlogs.Apply.Sample(代码已更新,并增加了 ...
- DDD 领域驱动设计-如何控制业务流程?
上一篇:<DDD 领域驱动设计-如何完善 Domain Model(领域模型)?> 开源地址:https://github.com/yuezhongxin/CNBlogs.Apply.Sa ...
- DDD 领域驱动设计-如何完善 Domain Model(领域模型)?
上一篇:<DDD 领域驱动设计-如何 DDD?> 开源地址:https://github.com/yuezhongxin/CNBlogs.Apply.Sample(代码已更新) 阅读目录: ...
- DDD领域驱动设计之领域服务
1.DDD领域驱动设计实践篇之如何提取模型 2.DDD领域驱动设计之聚合.实体.值对象 3.DDD领域驱动设计之领域基础设施层 什么是领域服务,DDD书中是说,有些类或者方法,放实体A也不好,放实体B ...
随机推荐
- 鸿蒙之后,小米 Vela 也来了,下一代物联网平台应该是什么?
1. 华为鸿蒙基于jerryscript构建物联网应用框架 2020年9月10日 鸿蒙OS 1.0 正式版发布,面向物联网领域,鸿蒙推出了类web开发架构ACE JS = LiteOS + jerry ...
- Python练手项目实例汇总(附源码下载)
今天给大家分享几个有趣的Python练手项目实例,希望对Python初学者有帮助哈~ 一.经典的俄罗斯方块 1. 绑定功能 1 # 绑定功能 2 class App(Frame): 3 def _ ...
- 关于mybatis拦截器,对结果集进行拦截
因业务需要,需将结果集序列化为json返回,于是,网上找了好久资料,都是关于拦截参数的处理,拦截Sql语法构建的处理,就是很少关于对拦截结果集的处理,于是自己简单的写了一个对结果集的处理, 记录下. ...
- SpringBoot+MySQL,如何整合并使用MyBatis框架
概述 MyBatis 是一款优秀的持久层框架,它支持定制化 SQL.存储过程以及高级映射.MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集. MyBatis 可以使用简单的 ...
- Spider_基础总结1_Request(get/post__url传参_headers_timeout)+Reponse
网络爬虫(一) 一.简介 1.robot协议(爬虫协议):这个协议告诉引擎哪些页面可以抓取,哪些不可以 -User-agent:爬虫引擎 -allow:允许robot访问的URL -disallow: ...
- 1. Spark的安装及介绍
*以下内容由<Spark快速大数据分析>整理所得. 读书笔记的第一部分是记录如何安装Spark?同时,简单介绍下Spark. 一.Spark安装 二.Spark介绍 一.Spark安装 如 ...
- python之迭代锁与信号量
如果现在需要在多处加锁大于等于2的时候 因为计算机比较笨,当他锁上一把锁的时候又所理一把锁,等他来开锁的时候他不知道用哪把钥匙来开锁, 所以这个时候我们需要把把平常的锁变为迭代锁 eg: import ...
- 编译一个支持多线程的php安装包
前言 因为项目上的需要,需要用到php,一般来说,用默认的版本和配置就可以满足大多数的场景,因为需要加入多线程,所以需要自己编译一个包 一般来说,发行的包的版本的配置选项和代码都是最稳定的,所以在大多 ...
- 使用Ganglia监控系统监控集群(debian)
ganglia是一个集群监控软件,底层使用RRDTool获得数据. Ganglia分为ganglia-monitor和gmetad两部分,前者运行在集群每个节点上(被监控机器)收集RRDTool产生的 ...
- [LeetCode题解]143. 重排链表 | 快慢指针 + 反转
解题思路 找到右边链表,再反转右边链表,然后按左.右逐一合并 代码 /** * Definition for singly-linked list. * public class ListNode { ...