赞
踩
DDD是一种针对大型复杂系统的领域建模与分析方法,它是一套方法论,试图分离技术实现的复杂性,建立了以领域为核心驱动力的设计体系。
DDD的解决问题思想是将复杂的问题细分为子问题域(分而治之),再逐个解决子问题域,当解决了所有子问题域后,就建立了完整地领域模型。
DDD的正确使用步骤:
【1】采用DDD的方法开始需求分析、领域建模,主键建立起多个问题子域
【2】将问题子域落实到限界上下文中,并梳理出上下文映射关系图
【3】将各个子域落实到微服务中的贫血模型、充血模型、实体、值类型、聚合、存储库、工厂和服务的设计中,依据上下文映射图形成微服务之间的接口
战略设计,通过建立限界上下文、统一语言和上下文映射对业务进行高层次的抽象和归类。
战略设计从业务视角出发,关注复杂业务的分解,通过将复杂业务分解为一个个小的子域以及相互之间的关联关系,可以指导团队协作和后续的战术设计。
战略设计的产出一般包括限界上下文、统一语言、问题域的划分(核心域、支撑域和能用域)、上下文映射。
领域即是一个组织在一个边界内所做的事情以及其中所包含的一切,即业务知识。业务有一些内在规则,存在专业性,比如财务、CRM、OA、电商等不同领域的业务规则不同。计算机只是业务规则的自动化。
子域是领域的一部分。
在DDD中,为了降低业务理解的复杂度,一个领域被划分为若干子域,每个子域都有一个清晰的限界上下文,领域模型在限界上下文中完成开发。在开发一个领域模型时,我们关注的通常只是这个业务系统的某个方面。
子域包括核心域、支撑域和通用域,将子域划分成不同的类型主要考虑到,公司在 IT 系统建设过程中,由于预算和资源有限,对不同类型的子域应有不同的关注度和资源投入策略。
通用语言是团队自己创建的公用语言,其中包括领域专家、开发、业务分析员等。在同一个限界上下文中,团队成员使用通用语言进行交流。通用语言会随着时间推移而不断的演化。
通用语言包含术语和用例场景,并且能够直接反映在代码中,有助于将业务需求直接转化为代码。通用语言中的名词可以给领域对象命名,如商品、订单等,对应实体对象;而动词则表示一个动作或事件,如商品已下单、订单已付款等,对应领域事件或者命令。
限界上下文与通用语言存在一对一的关系。
核心域是指领域中最核心的部分,通常对应企业的核心业务和核心竞争力,也是业务成功的主要促成因素。
从战略层面上讲,应该给核心域最高的优先级、最资深的领域专家和最优秀的开发团队。
支撑域是一种特殊的子域,是指为了实现核心业务而不得不开发的业务所对应的相关知识的集合。支撑域对应着业务的某些重要方面,类似于定制开发,但却不是核心。对它的投入无论如何也达不到与核心域相同的程度,甚至可以考虑使用外包的方式实现此类限界上下文,
例如,活动平台业务属于电商的支撑域,因为该业务对于电商企业并不是必需的,其存在的意义仅在于放大利润。
通用域是另一种特殊的子域,没有太多的个性化述求,对应的是业界已经有成熟方案的业务。
通用域可以看做一种特殊的支撑域,可以使用标准部件来实现,短信通知、邮件等领域问题。
限界上下文包括限界和上下文两个词,限界代表领域的边界,上下文代表通用语言的语境,综合表示应用程序的一个概念性边界。在这个边界之内的每种领域术语、词组或句子–即通用语言,都有确定的上下文含义。在边界之外,这些述语可能表示不同的意思。
在 DDD 实践中领域模型会被限定在限界上下文当中。
限界上下文强调概念的一致性。虽然传统的方法学已经在追求概念的一致性,但是忽略了系统的庞大性,不论系统多庞大,在系统任何位置同一概念通用。DDD 不追求全局的一致性,而是将系统拆成多块,在相同的上下文中实现概念一致性。
识别上下文可以从概念的二义性着手,比如商品的概念在物流、交易、支付含义完全不一样,但具有不同内涵和外延,实际上他们处在不同上下文。
限界上下文主要用来封装通用语言和领域对象,但同时它也包含了那些为领域模型提供交互手段和辅助功能的内容,如应用服务、数据库Schema。
限界上下文可以用于微服务划分、避免模型的不正确复用带来的问题。
业务所面临的挑战。
问题空间是领域的一部分,对问题空间的评估应该同时考虑已有子域和额外所需子域。
解决业务所面临的挑战的解决方案集合。
解决方案空间包括一个或多个限界上下文,即一组特定的软件模型。
上下文映射表示不同限界上下文在解决方案空间中是如何通过集成相互关联的。
其中U代表upstream,D代表downstream,下游依赖上游。
在上下文映射中需要特别注意循环依赖、双向依赖和过长的依赖,如果出现这几种依赖关系,需要思考限界上下文分解的是否合理。
限界上下文之间的低耦合是指限界上下文之间通过接口调用,如C上下文依赖A上下文和B上下文,只要B上下文实现了A上下文的接口,C上下文可以只依赖B上下文。
战术设计则从技术视角出发,侧重于领域模型的技术实现,完成软件开发和落地,包括:聚合根、实体、值对象、领域服务、应用服务和资源库等代码逻辑的设计和实现。
实体是具有唯一身份标识的对象。
实体的特征:
//实体
public class Product extends Entity {
//实体的身份标识为一个值对象
private ProductId productId;
private ActivePolicy activePolicy;
...
public Product(ProductId productId) {
this.setProductId(productId);
}
public Date creationDate() {
this.productId().creationDate();
}
//省略setter和getter
}
//值对像
public class ProductId extends ValueObject{
private static final SimpleDateFormat DEFAULT_DATE_FORMATTER = new SimpleDateFormat("yyyyMMdd");;
private String productId;
public ProductId(UUID uuid) {
this.productId = "APM-P-" + DEFAULT_DATE_FORMATTER.format(new Date()) + "-" + uuid.substring(0,10)
}
public Date creationDate() {
return DEFAULT_DATE_FORMATTER.parse(this.productId.split("-")[2]);
}
}
//获取ProductId
public interface ProductRepository {
default ProductId nextId() {
return new ProductId(UUID.randomUUID());
}
值对象表示属性集合,将多个相关属性组合为一个不可修改的概念整体。
值对象的特点:
领域服务表示一个无状态的操作,它用于实现特定于某个领域的任务。
领域服务主要用于如下场景:
在实现领域服务时,如果一个领域服务只有一种实现且并非一个技术上的实现(如与其他服务或基础设施进行集成等),通常没有必要为领域服务声明一个接口。
领域事件表示领域中所发生的事情,通常会导致进一步的业务操作。每个事件用领域对象表示。
领域事件的产生、存储、转发和订阅:
领域事件的适用场景:
领域事件建模:
领域事件的基本属性:
模块表示一个命名的容器,用于存放领域中内聚在一起的类。模块应该包含一级具有高内聚的概念集合,将类放在不同模块中的目的在于达到松耦合性。
设计模块的简单原则:
示例:
com.thoughtworks(组织顶级域名).agilepm(限界上下文).domain(分层).model(模块).team(具体模块)
com.thoughtworks.agilepm.domain.model.project
com.thoughtworks.agilepm.domain.model.product
com.thoughtworks.agilepm.domain.model.product.backlogitem
com.thoughtworks.agilepm.domain.model.product.release
com.thoughtworks.agilepm.domain.model.product.sprintt
聚合由多个领域对象(实体和值对象)在一致性边界之内组成(概念上体现的是整体与部分的关系,代码实现上体现在聚合是数据修改和持久化的基本单元,每一个聚合对应一个仓储)。定义一个聚合通常包括两部分:
聚合的完整性规则通常包括:
设计聚合的注意事项:
聚合根主要为了解决复杂业务模型由于缺少统一的完整性规则,而导致的聚合实体间的数据不一致问题。
如果把聚合比作组织,那聚合根就是这个组织的负责人。聚合根也称为根实体,它不仅是实体,还是聚合的管理者。
聚合根的作用包括:
作为实体,具有实体的属性和业务行为,能够实现业务逻辑
作为聚合的管理者,在聚合内部直接引用实体和值对象,负责协调实体和值对象按照固定的业务规则协同完成共同的业务逻辑
在聚合之间,是聚合对外的接口人,以聚合根 ID 关联的方式接受外部任务和请求,在上下文内实现聚合之间的业务协同
通过存储库(Repository)完成对数据库的访问。
与DAO的区别:
注意与工厂设计模式的差别,工厂设计模式是降低调用方与被调用方的耦合度,而DDD的工厂是为了装配领域对象,是领域对象生命周期的起点。
分别调用各个DAO获得相应的数据,再将这些数据组装成领域对象。
通过存储库与工厂,对原有的DAO进行了一层封装,在保存、装载、查询等操作中,加入聚合、装配等操作,并将这些操作封装起来,对上层的客户程序屏蔽。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。