大话DDD — 服务、实体、值对象、聚合根

基于DDD的程序设计,就是将前面的领域模型映射成数据架构中的程序设计,从而通过领域驱动提升软件设计质量,那么应该进行映射,让领域模型指导程序设计。

要将领域模型映射成程序设计,最终都要落实到三种类型的对象设计:服务、实体、值对象。

领域服务

有些领域的动作,他们是一些动词,看上去却不属于任何对象,它们代表了领域中的一个重要的行为,所以不能忽略他们或者简单地把它们合并到某个实体或者值对象中。当这样的行为从领域中被识别出来时,最佳实践是把它声明成一个服务。这样的对象不再拥有内置的状态。他的作用仅仅是为领域提供相应的能力。Service往往是以一个活动命名,而不是Entity来命名。

例如在转账的例子中,转账(transfer)这个行为是一个非常重要的领域概念,但是它是发生在两个账户之间的,归属于实体并不合适,因为一个账户实体没有必要去关联他需要转账的账户实体,这种情况下,使用领域服务(MoneyTransferDomainService)就比较合适了。

识别领域服务,主要看它是否满足以下三个特征:

  1. 服务执行的操作代表了一个领域概念,这个领域概念无法自然地隶属于一个实体或者值对象。
  2. 被执行的操作涉及到领域中的其他的对象;
  3. 操作是无状态的;

实体

我们的软件系统。毫不夸张地说,就是对现实世界的真实模拟。现实世界的事物,在软件世界中就就被模拟成一个对象。该事物在现实世界中赋予什么职责,在软件世界中就被赋予什么职责;在现实世界中拥有什么特效,在软件世界中就拥有什么属性;在现实世界中拥有什么行为,在软件世界中就拥有什么函数;在现实世界中与哪些事物存在怎样的关系,在软件世界中就应当与它们发生怎样的关联。这正是面向对象编程的核心思想。也就是DDD中,寻找领域实体的核心思想。

现实世界VS软件世界.png

实体:通过一个唯一标识字段来区分真实世界中的每一个个体的领域对象。当一个对象由其标识(而不是属性)区分时,这个对象称为实体(Entity)

  • 例如:公安系统的身份信息录入,对于人的身份信息可以认为是实体,因为每个人是独一无二,且具有唯一标识,且随着时间的推移人的年龄,身高,外貌会进行变化,但是标识不变。

在实践上建议将属性的校验放到实体中。

值对象

值对象:代表的是真实世界中哪些一成不变、本质性的事物,这样的领域对象叫做“值对象”。当一个对象用于对事物进行描述而没有唯一标识时,它被称为值对象。

  • 例如:颜色信息,我们只需要知道{“name”:“黑色”,”css”:“#000000”}这样的值信息就能够满足要求,这避免了我们对标识追踪带来的系统复杂性。

在实践中,需要保证值对象创建后就不能被修改,即不允许外部载修改其属性。在不同上下文集成时,会出现模型概念的公用,如商品模型会存在于电商的各个上下文中。订单上下问中如果只关注下单时商品信息的快照,那么就商品对象视为值对象是很好的选择。

可变性是实体的特点,不变性是值对象的本质。

聚合根

聚合根:是一组相关对象的集合,作为一个整体被外界访问,聚合根就是这个聚合的根节点。聚合描述的整体与部分的关系:当整体不存在时,部分就变得没有意义。

  • 例如:在DSP平台去创建要投放的广告订单时,我们可以将广告订单当做一个聚合根。广告订单中的投放目标(例如激活、付费等)与广告订单没有整体与部分关系。那么投放目标可以看做一个小聚合根对象。广告订单可以看着大聚合根对象(内部包含的投放目标作为值对象)。在创建广告订单时需要对投放目标进行校验,故创建广告订单实体时—可以先构建投放目标的实体(内部包含 账户信息作为值对象,投放订单部分信息作为值对象)去调用投放目标的领域服务。然后进行逻辑校验。

聚合根操作规范:

  1. 聚合根具有全局标识,最终负责检查规定规则;
  2. 聚合内的实体具有本地标识,这些标识在聚合内部才是唯一的;
  3. 外部对象不能引用除根实体之外的任何内部对象;
  4. 只有聚合的根实体才能直接通过数据库查询获取,其他对象必须通过遍历关联来发现;
  5. 聚合内部的对象可以保持对其他聚合根的引用;
  6. 聚合边界内的任何对象修改时,整个聚合的所有固定规则都必须满足。

以银行为例:Account账户是CustomerInfo实体(客户信息)和Address(值对象)的聚合根,Tansaction(交易)是流水(Journal)的聚合根,因为流水是因为交易才产生的,具有相同的生命周期。

聚合根示例.png

如何创建好的聚合?

  • 是否是整体与部分的关系,即聚合的部分是否完全依赖于整体,例如订单与订单明细的关系是聚合,但是订单与用户并不是聚合。
  • 边界内的内容能否具有一致性:在事务中只修改一个聚合实例。如果你发现边界内很难接受强一致,不管出于性能或者产品需求的考虑,应该剥离出独立的聚合,采用最终一致的方式。
  • 设计小聚合:大部分的聚合都可以只包含根实体,而无需包含其他实体。即使一定要包含,可以考虑将其创建为值对象。
  • 通过唯一标识来引用其他聚合或实体:当存在对象之间的关联时,建议引用其唯一标识而非引用其整体对象。如果是外部上下文中的实体,引用其唯一标识或将需要的属性构造值对象。如果聚合创建复杂,推荐使用工厂方法来屏蔽内部复杂的创建逻辑。

领域驱动设计在互联网业务开发中的实践

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,736评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,167评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,442评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,902评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,302评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,573评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,847评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,562评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,260评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,531评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,021评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,367评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,016评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,068评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,827评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,610评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,514评论 2 269

推荐阅读更多精彩内容