前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >领域驱动设计——术语篇

领域驱动设计——术语篇

原创
作者头像
liliane
发布2022-07-27 22:42:32
7040
发布2022-07-27 22:42:32
举报
文章被收录于专栏:liliane随笔liliane随笔

随着微服务架构的普及,领域驱动设计(DDD)又重回软件设计战场。虽然团队内不少项目已经开始尝试,使用DDD指导项目的设计与开发,但还是有不少同学对DDD缺乏基础了解。因此,本文结合书本的定义及个人理解,对DDD中关键概念进行梳理,避免沟通时的歧义。毕竟DDD提倡使用通用语言,业务层面应该使用通用语言,技术层面也应该统一术语。

主要概念

  • 通用语言(Ubiquitous Language)

围绕领域模型建立的一种语言,团队所有成员都使用这种语言把领域的所有活动与软件联系起来。

通用语言是事件风暴中产生的,达成共识的、能够准确描述业务涵义和规则的语言。《领域驱动设计》一书对通用语言的重要性进行了较大篇幅的强调,在整个软件生命周期中,无论是口头交流还是书面表达都应该使用通用语言。

个人认为,对团队新成员进行通用语言培训是有必要的。

  • 实体(Entity)

一种对象,它不是由属性来定义的,而是通过一连串的连续事件和标识定义的。

实体和值对象都是领域知识中的名词,建模时,常常容易混淆。其关键判断依据是,实体是有标识的,要么是全局唯一标识,要么是聚合内部的本地标识。例如,订单ID是全局唯一标识,而订单项ID只需要在订单ID下唯一即可。

  • 值对象(Value Object)

一种描述了某种特性或属性,但没有概念标识的对象。

值对象是由其关键属性决定的,只要关键属性相同,就表示对象相同。值对象应保持其不变性,变更应整体替换。

在实现时,可能表现为在上下文A中为实体,在上下文B中为值对象。例如,“地址”,在订单上下文,它是值对象。但在地址维护子系统,它是实体。修改订单地址,实际上是通过重新选择地址对象,以json字符串等的方式存储于订单实体。地址系统的信息变更,并不会影响到已有订单。

  • 服务(Service)

一种作为接口提供的操作,它在模型中是独立的,没有封装的状态。

服务是无状态的,客户使用它时,不需要关心它的历史。服务在系统运行中通常以单一实例存在,它包含实现了各种业务逻辑的方法。DDD中的服务包括应用层服务和领域层服务。实践中,我们使用Facade命名应用层,它通过封装领域层服务,对外提供接口级别的服务。

  • 仓储(Repository)

一种把存储、检索和搜索行为封装起来的机制。

可以把它看做一个特殊的服务,它专门提供存储相关接口,上层访问与底层实际存储无关。但作为开发人员,仍需了解Repository各接口的实现细节,避免误用导致的性能等问题。

Repository通常可以支持用户定制化的接口(用户指定操作字段等,需要警惕SQL注入问题)和一些常用接口。例如,exec接口,允许用户指定数据表、字段,甚至操作。

  • 固定规则

一种为某些设计元素做出的断言,除了一些特殊的临时情况(例如,方法执行中间,或者尚未提交的数据库事务的中间)意外,它必须一直保持为真。

包括数据一致性规则、必填字段等。例如,订单总价=所有订单项价格 - 各种折扣。

  • 聚合(Aggregate)

聚合是一组相关对象的集合,我们把聚合作为数据修改的单元。

聚合根:聚合中一个代表聚合核心概念的实体。每个聚合有且仅有一个聚合根。

外部只能通过引用聚合根,查询、修改聚合内部数据。聚合内应保持固定规则,即符合数据一致性。

聚合是领域模型的第一层边界,通过组合、拆分聚合,构成微服务单元。

聚合间的调用逻辑应通过应用层服务RPC实现,以确保聚合间的低耦合,便于微服务的重组和拆分。

* 聚合的识别是实际操作中的难点,可以采用自下而上的方法,先将每个实体作为一个聚合,不断组合出合适聚合。

  • 限界上下文(Bounded Context)

限界上下文是规定了领域边界的语义环境,领域内使用通用语言。

它是领域模型的第二层边界,一个限界上下文应包含应用层、领域层、数据层。在软件设计初期,不同限界上下文可能会共享数据库,以降低成本,但仍需要注意分库,或者分表,并避免联合查询,及表间外键的级联更新、删除。

限界上下文可以作为微服务的边界

  • 工厂(Factory)

一种封装机制,把复杂的创建逻辑封装起来,并为客户抽象出所创建的对象的类型。

包括创建工厂和重建工厂(来自存储或网络的数据重建)。

一般对象(包括实体和值对象)的创建有两种方式,简单的对象创建可以由构造函数(Go中没有静态方法,可以用函数)实现;复杂的对象(通常是聚合根)的创建,可以由工厂方法实现。

工厂创建出来的对象必须满足固定规则。固定规则的逻辑根据是否在全生命周期使用,可放置在实体,若仅在创建时校验,可放置在工厂。

实体工厂创建出来的对象仅包含必填字段即可。值对象工厂创建出来的值对象需包含全部字段,因为值对象是不可变的。

  • 领域事件(Domain Event)

领域事件通常是领域知识中的,“当xxx完成,则执行xxx”,当领域事件发生,将进一步触发业务操作。

领域事件是微服务解耦的关键。对非实时一致性场景,事件通过发布、订阅方式实现,达到最终一致性。

领域事件避免了传统RPC的分布式事务难题,减轻了系统实时访问的压力。

* 为了确保可靠性,应根据需要对事件进行持久化

(个人理解和以往的“事件”没有太大区别,重点是识别出领域事件)

  • 贫血模型

领域对象只有属性及其getter/setter方法的纯数据类,业务逻辑通过服务实现。传统的三层架构中的数据类就是这种模式。

  • 充血模型

单个、自身的业务逻辑属于领域对象的行为。

涉及多个领域对象交互的部分属于领域层的服务,其他领域无关的、跨聚合的逻辑属于应用层服务。

参考文献

《领域驱动设计——软件核心复杂性应对之道》

《实现领域驱动设计》

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 主要概念
  • 参考文献
相关产品与服务
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
http://www.vxiaotou.com