一 DDD是一种业务分析方法
这里首推ENode作者汤雪华的博客。
DDD领域驱动设计是计算机软件行业为了项目能尽量趋向成功,根据多年经验总结出来的一套业务分析的方法论。其核心是消化特定业务领域的知识并创建忠实反映它的软件模型。
DDD的分析部分 顶层设计
电子商务就是 问题空间 管理后台可能对应一个sln 就是一个解决方案空间
核心思想 分而治之
分析部分最擅长处理两种场景
一种是 业务复杂
另一种 是 业务逻辑还没完全清除 比如初创企业
一个解决方案中容纳多个BC 可以用命名空间的方式来体现BC的隔离
分析BC内的业务 就需要聚合和实体的概念
实体 领域中具有唯一标识的对象 ABP中有实体的泛型基类Entity 其中主要就是一个属性ID 其他的FullAuditedEntity或者CreationAuditedEntity 都是框架提供方便审计的基类扩展
从命名空间上看 我们给BC一个名字 让他逻辑统领一份部分代码 这些代码主要就是实体类
实体类也有主次 典型例子就是ORder实体和OrderItem 虽然OrderItem有ID也是实体 但是单条OrderItem几乎没有业务意义 所以对OrderItem的操作通过对Order 代理 这里的Order就是聚合根
把一组实体放在一起就是聚合 最有代表的实体就是聚合根 聚合之间 只能通过聚合根进行引用 不能直接引用聚合中的 非聚合根实体
按order来说 其他聚合要引用order 的时候 记录的是OrderId 或者订单号 假设其他聚合要处理Order的OrderItem 野只能引用Order 让Order去处理OrderItem 这就是内聚的思想 或者叫封装
或者叫关注点隔离
一开是看到Abp的 AggregateRoot和IAggregeateRoot的时候 都是蒙的 项目模板也没有这个基类的范例 再看看 这个基类提供的属性 DomainEvents 以及abp框架中涉及该属性机制的源码
(看AbpDbcontext的savechange方法实现) 这时候 我们看到了事件怎么用 开始思考领域事件这个词 开始去学习DDD
当我们开始思考事件的时候 我们很自然的就回去思考实体的行为
我们通过实体方法实现实体自己能够处理的业务逻辑 以 Tell not ask 的原则实现实体的行为 在行为成功完成后 抛出事件 以便外部协同 而聚合根(继承AggregateRoot基类或者实现IAggregateRoot接口)作为其他实体的代理 实现本聚合内的逻辑 通过 DomanEvents收集各类事件 交由Abp框架底层来触发事件 实现跨聚合甚至跨BC的协同(同时事件的发布订阅模式也是一种逻辑代码的
解耦。顺序无关 EventHandler也可以回滚工作单元)
另外 DDD的仓储模式是基于聚合根实体的(聚合根同时代理了非聚合根实体的仓储职责,就是说OrderItem不应有自己的仓储接口和实现)这一点在ABp中没有严格限制 或许是abp作者不希望把框架的使用门槛定的太高
实体(聚合根也是实体) 只能实现自己范围内的业务逻辑 那范围外呢 (个人思考 是不是实体的业务逻辑相当于dal 领域服务相当于bll)
所有无法放到单个实体内的业务逻辑 都可以放到领域服务中去实现
这包含 需要同一个实体类的多个实例配合的 需要不同实体类的多个实例去配合的 还有其他 只要是一个实体的实例无法完成自己的逻辑 就需要构建领域服务
最后 最小的DDD构建 值对象 ABP框架中有一个基类 Value Object 即用来表示 值对象
其实 DDD中的值对象对应到代码 有一个很宽泛的范围 可以认为
所有没有唯一标识数据的数据对象 都是值对象
最基本的 比如C#语言的值类型 像string int decimal 都是值对象 那么我们为什么还需要一个基类来辅助构造值对象
第一个原因是 值类型 业务表达能力弱
通过float 我们可以知道数量 但是不知道是重量还是体积
通过decimal 我们能标识金额 但是不知道是人民币还是美元
所以我们需要自己构建值对象 来更准确的表达业务概念
第二个原因是 方便
值对象只能通过各个属性的具体值来比较来唯一确定 这个基类帮我们重写了equals()和GetHashCode() 并重载了相等和不相等操作符
电脑实这里有个坑
值对象 必须保证其不变性
具体看abp谢列 为什么值对象必须设计成不可变的 而abp框架是无法控制你如何使用Valueobject的子类的 具体的说
你的值对象必须关闭所有属性的setter 必须通过构造函数来初始化 且不允许通过方法去改变值属性
上面讲的基本都是领域层
DDD将领域模型支撑架构的时候 特别提到了 封层 也是我们从abp中学到的分层方式 表现层 应用服务层 领域层 基础设施层
表现层并不特指前端界面 mvc框架也只是一种表现层框架 他只是特别擅长处理http协议
应用服务层就是application程序集 是ddd建议的体现用例的一层 直接对接表现层(类似mvc控制器的协调作用 接受请求 返回dto) 用来编排任务 将工作指派给下层 所以应用服务的代码根据用例进行组织即可 (用例)
领域层即是业务模型的完整实现 (如果是完整实现 为什么还需要应用服务层)
基础设施层侧重于持久化技术 比如ef 但是不限于持久化技术 (通用功能接口的具体技术实现 类似仓储 , 接口定义在领域层 实现放在基础设施层) abp按照orm框架名称作为基础设施层的程序集命名可以理解 但是不能被其限制 个人建议另开一个程序集比如 Personball.Demo.Infrastructure 依赖与Personball.Demo.EntiyFramework 再让启动模块依赖infrastruture模块
扩展 CQRS和事件溯源
当我们说起经点领域模型的的时候 指的就是基于对象模型来实现业务 数据存储走关系型数据库 一切看起来很完美
但是DDD研究的是复杂性
软件开发行业几十年的经验积累下 前辈们发现如果把软件功能分成两个方面 假设系统中查询部门的复杂度是N 命令(创建或者变更数据)部分的复杂度也是N
那么经点领域模型的情况下 系统的命令和查询混在一起 这个总体复杂度就是N乘以N 如果分开 那么美系统总体复杂度就会降低到N+N
另一种说法是 对象模型的局限性日益显现 现在发现关注事件比关注对象更方便业务建模 因为现实世界是基于事件的 这引导我们可以用函数式编程来实现支撑架构 同时也引出了事件溯源架构
CQRS 命令与查询职责分离 正如其字面上的意思 一个相当简单的原则 却非常有效的降低了系统的复杂性
这里ing不是要推荐一个CQRS开发框架 只是提一下 大家可以在任何开发框架 任何场景下 按CQRS的方式去思考 都可以获得实际的好处
再理一遍
统一语言
问题空间 子领域
解决方案空间 绑定上下文 /上下文呢映射。 聚合/聚合根 实体 值对象
原文地址 : http://www.360doc.com/content/18/1209/07/46368139_800353846.shtml