我写这篇博客的动机是想分享一些关于聚合的理解——它们是什么以及它们为什么重要。在过去的几个月里,我经历了从对DDD一无所知到深入研究DDD的痛苦,我希望它能帮助初学者,因为他们可能要经历同样的事情。
聚合是概念上属于一起的实体和值对象(域对象)的封装。它还包含一组可以对这些域对象进行操作的操作。
例如,聚合可以是一辆汽车,其中封装的域对象可以是引擎、车轮、车身颜色和灯光;类似地,在制造汽车的环境中,操作可能是:车身油漆、安装轮、安装引擎、安装灯和船。您的业务规则可能是:
- 一辆准备装运的汽车必须有四个轮子
- 没有黄色汽车被制造出来
- 车身喷漆后必须安装车灯
- 一辆准备装运的汽车必须正好有16盏灯
- 一辆准备装运的汽车必须有一个发动机和一个油漆过的车身
在不过度批判我对汽车和汽车制造的知识的情况下,我们在c#中有以下集合:
public class Car { public Engine Engine { get; private set; } private List<Wheel> _wheels; public IReadOnlyList<Wheel> Wheels => _wheels; public string BodyColour { get; private set; } private List<Light> _lights; public IReadOnlyList<Light> Lights => _lights; public bool IsShipped { get; private set; } public Car(List<Light> lights, List<Wheel> wheels, string bodyColour, Engine engine, bool isShipped) { _lights = lights; _wheels = wheels; BodyColour = bodyColour; Engine = engine; IsShipped = isShipped; } public void PaintBody(string colour) { if (colour == "yellow") { throw new ArgumentException("No yellow cars are allowed"); } if (_lights.Count > 0) { throw new ArgumentException("Some lights are already installed"); } BodyColour = colour; } public void InstallLight() { if (_lights.Count == 16) { throw new ArgumentException("Lights are fully installed"); } if (BodyColour != null) { throw new ArgumentException("Body is already painted"); } } public void InstallEngine(Engine engine) { Engine = engine; } public void InstallWheel(Wheel wheel) { if (_wheels.Count == 4) { throw new ArgumentException("Wheels are already fully installed"); } _wheels.Add(wheel); } public void Ship() { if (_wheels.Count != 4) { throw new ArgumentException("Wheels are not fully installed yet"); } if (_lights.Count != 16) { throw new ArgumentException("Lights are not fully installed yet"); } if (Engine == null) { throw new ArgumentException("Engine is not installed yet"); } if (BodyColour == null) { throw new ArgumentException("Body is not painted yet"); } IsShipped = true; } }
聚合是数据存储传输的基本元素——请求加载或保存整个聚合。事务不应该跨越聚合边界。
-马丁
在本例中,当您从持久层检索Car对象时,您必须检索它的引擎、灯光、车轮和车身颜色。类似地,在保存时,还必须保存这些属性。
为什么这个模式很重要?
聚合本质上是关于定义一致性边界和加强不变性的。
一致性边界是聚合定义的边界。在汽车制造的大背景下,Car保持了汽车制造规则的一致性。不变量只是规则的一个花哨的词。它通过保持Car对象的一致性来执行这些规则。这样做有几个好处:
- 鼓励采用自顶向下的方法,其中实现由业务需求决定
- 作为一个抽象层,因此允许应用程序是持久性的未知的
通常,一组定义良好的聚合会覆盖整个持久性层。这意味着业务规则只有一个单一的事实来源,这使得以下工作很容易:
- 适应业务需求的变化
- 新加入项目的开发人员要确定项目是关于什么的
风险和缓解
聚合是向持久层写入模型的基础。拥有一组定义良好的聚合是绝对重要的。一组定义良好的聚合是什么样的?
- 首先,集合中的不变量必须是成对互斥的。这意味着两个聚合体不能有重叠的不变量和实体,这些不变量和实体可能相互冲突,也可能相互不冲突。这样做的结果是,您的数据存储之间可能存在不一致的地方。
- 其次,如果一个集合变得很大,并且有许多域对象,通常这意味着检索/更新数据存储的性能会降低,这显然很大程度上取决于所使用的数据存储的类型。
原文:https://medium.com/ingeniouslysimple/aggregates-in-domain-driven-design-5aab3ef9901d
本文:https://pub.intelligentx.net/node/822
讨论:请加入知识星球【首席架构师圈】或者飞聊小组【首席架构师智库】
- 登录 发表评论
- 46 次浏览
最新内容
- 1 week ago
- 1 week ago
- 1 week ago
- 1 week ago
- 1 week ago
- 1 week 6 days ago
- 1 week 6 days ago
- 2 weeks 2 days ago
- 2 weeks 2 days ago
- 2 weeks 2 days ago