精通网站开发,网站策划 英文,全国思政网站的建设情况,东莞医疗网站建设报价文章目录 领域对象的整理从领域模型到微服务的设计领域层的领域对象应用层的领域对象 领域对象与微服务代码对象的映射典型的领域模型非典型领域模型 DDD 强调先构建领域模型然后设计微服务#xff0c;以保证领域模型和微服务的一体性#xff0c;因此我们不能脱离领域模型来谈… 文章目录 领域对象的整理从领域模型到微服务的设计领域层的领域对象应用层的领域对象 领域对象与微服务代码对象的映射典型的领域模型非典型领域模型 DDD 强调先构建领域模型然后设计微服务以保证领域模型和微服务的一体性因此我们不能脱离领域模型来谈微服务的设计和落地。但在构建领域模型时我们往往是站在业务视角的并且有些领域对象还带着业务语言。我们还需要将领域模型作为微服务设计的输入对领域对象进行设计和转换让领域对象与代码对象建立映射关系。
领域对象的整理
完成微服务拆分后领域模型的边界和领域对象就基本确定了。我们第一个重要的工作就是整理事件风暴过程中产生的各个领域对象比如聚合、实体、命令和领域事件等内容将这些领域对象和业务行为记录到下面的表格中。可以看到这张表格里包含了领域模型、聚合、领域对象和领域类型四个维度。一个领域模型会包含多个聚合一个聚合包含多个领域对象每个领域对象都有自己的领域类型。领域类型主要标识领域对象的属性比如聚合根、实体、命令和领域事件等类型。
从领域模型到微服务的设计
从领域模型到微服务落地我们还需要做进一步的设计和分析。事件风暴中提取的领域对象还需要经过用户故事或领域故事分析以及微服务设计才能用于微服务系统开发。这个过程会比事件风暴来的更深入和细致。主要关注内容如下 分析微服务内有哪些服务服务所在的分层应用服务由哪些服务组合和编排完成领域服务包括哪些实体的业务逻辑采用充血模型的实体有哪些属性和方法有哪些值对象哪个实体是聚合根等最后梳理出所有的领域对象和它们之间的依赖关系我们会给每个领域对象设计对应的代码对象定义它们所在的软件包和代码目录。 这个设计过程建议参与的角色有DDD 专家、架构师、设计人员和开发经理。
领域层的领域对象
事件风暴结束时领域模型聚合内一般会有聚合、实体、命令和领域事件等领域对象。在完成故事分析和微服务设计后微服务的聚合内一般会有聚合、聚合根、实体、值对象、领域事件、领域服务和仓储等领域对象。
1. 设计实体
大多数情况下领域模型的业务实体与微服务的数据库实体是一一对应的。但某些领域模型的实体在微服务设计时可能会被设计为多个数据实体或者实体的某些属性被设计为值对象。我们分析个人客户时还需要有地址、电话和银行账号等实体它们被聚合根引用不容易在领域建模时发现我们需要在微服务设计过程中识别和设计出来。在分层架构里实体采用充血模型在实体类内实现实体的全部业务逻辑。这些不同的实体都有自己的方法和业务行为比如地址实体有新增和修改地址的方法银行账号实体有新增和修改银行账号的方法。实体类放在领域层的 Entity 目录结构下。
2. 找出聚合根
聚合根来源于领域模型在个人客户聚合里个人客户这个实体是聚合根它负责管理地址、电话以及银行账号的生命周期。个人客户聚合根通过工厂和仓储模式实现聚合内地址、银行账号等实体和值对象数据的初始化和持久化。聚合根是一种特殊的实体它有自己的属性和方法。聚合根可以实现聚合之间的对象引用还可以引用聚合内的所有实体。聚合根类放在代码模型的 Entity 目录结构下。聚合根有自己的实现方法比如生成客户编码新增和修改客户信息等方法。
3. 设计值对象
根据需要将某些实体的某些属性或属性集设计为值对象。值对象类放在代码模型的 Entity目录结构下。在个人客户聚合中客户拥有客户证件类型它是以枚举值的形式存在所以将它设计为值对象。有些领域对象可以设计为值对象也可以设计为实体我们需要根据具体情况来分析。如果这个领域对象在其它聚合内维护生命周期且在它依附的实体对象中只允许整体替换我们就可以将它设计为值对象。如果这个对象是多条且需要基于它做查询统计建议将它设计为实体。
4. 设计领域事件
如果领域模型中领域事件会触发下一步的业务操作我们就需要设计领域事件。首先确定领域事件发生在微服务内还是微服务之间。然后设计事件实体对象事件的发布和订阅机制以及事件的处理机制。判断是否需要引入事件总线或消息中间件。在个人客户聚合中有客户已创建的领域事件因此它有客户创建事件这个实体。领域事件实体和处理类放在领域层的 Event 目录结构下。领域事件的发布和订阅类建议放在应用层的 Event 目录结构下。
5. 设计领域服务
如果一个业务动作或行为跨多个实体我们就需要设计领域服务。领域服务通过对多个实体和实体方法进行组合完成核心业务逻辑。你可以认为领域服务是位于实体方法之上和应用服务之下的一层业务逻辑。按照严格分层架构层的依赖关系如果实体的方法需要暴露给应用层它需要封装成领域服务后才可以被应用服务调用。所以如果有的实体方法需要被前端应用调用我们会将它封装成领域服务然后再封装为应用服务。个人客户聚合根这个实体创建个人客户信息的方法被封装为创建个人客户信息领域服务。然后再被封装为创建个人客户信息应用服务向前端应用暴露。领域服务类放在领域层的 Service 目录结构下。
6. 设计仓储
每一个聚合都有一个仓储仓储主要用来完成数据查询和持久化操作。仓储包括仓储的接口和仓储实现通过依赖倒置实现应用业务逻辑与数据库资源逻辑的解耦。仓储代码放在领域层的 Repository 目录结构下。
应用层的领域对象
应用层的主要领域对象是应用服务和事件的发布以及订阅。在事件风暴或领域故事分析时往往会根据用户或系统发起的命令来设计服务或实体方法。为了响应这个命令需要分析和记录 在应用层和领域层分别会发生哪些业务行为各层分别需要设计哪些服务或者方法这些方法和服务的分层以及领域类型比如实体方法、领域服务和应用服务等它们之间的调用和组合的依赖关系。 在严格分层架构模式下不允许服务的跨层调用每个服务只能调用它的下一层服务。服务从下到上依次为实体方法、领域服务和应用服务。如果需要实现服务的跨层调用我们应该怎么办建议采用服务逐层封装的方式。 服务的封装和调用主要有以下几种方式
实体方法的封装实体方法是最底层的原子业务逻辑。如果单一实体的方法需要被跨层调用你可以将它封装成领域服务这样封装的领域服务就可以被应用服务调用和编排了。如果它还需要被用户接口层调用你还需要将这个领域服务封装成应用服务。经过逐层服务封装实体方法就可以暴露给上面不同的层实现跨层调用。封装时服务前面的名字可以保持一致你可以用 *DomainService 或 *AppService 后缀来区分领域服务或应用服务。领域服务的组合和封装领域服务会对多个实体和实体方法进行组合和编排供应用服务调用。如果它需要暴露给用户接口层领域服务就需要封装成应用服务。应用服务的组合和编排应用服务会对多个领域服务进行组合和编排暴露给用户接口层供前端应用调用。在应用服务组合和编排时你需要关注一个现象多个应用服务可能会对多个同样的领域服务重复进行同样业务逻辑的组合和编排。当出现这种情况时你就需要分析是不是领域服务可以整合了。你可以将这几个不断重复组合的领域服务合并到一个领域服务中实现。这样既省去了应用服务的反复编排也实现了服务的演进。这样领域模型将会越来越精炼更能适应业务的要求。应用服务类放在应用层 Service 目录结构下。领域事件的发布和订阅类放在应用层 Event目录结构下。
领域对象与微服务代码对象的映射
典型的领域模型
个人客户领域模型中的个人客户聚合就是典型的领域模型从聚合内可以提取出多个实体和值对象以及它的聚合根。我们看一下下面这个图我们对个人客户聚合做了进一步的分析。提取了个人客户表单这个聚合根形成了客户类型值对象以及电话、地址、银行账号等实体为实体方法和服务做了封装和分层建立了领域对象的关联和依赖关系还有仓储等设计。关键是这个过程我们建立了领域对象与微服务代码对象的映射关系。 层定义领域对象位于分层架构中的哪一层比如接口层、应用层、领域层以及基础层等。领域对象领域模型中领域对象的具体名称。领域类型根据 DDD 知识体系定义的领域对象的类型包括限界上下文、聚合、聚合根、实体、值对象、领域事件、应用服务、领域服务和仓储服务等领域类型。依赖的领域对象根据业务对象依赖或分层调用的依赖关系建立的领域对象的依赖关系比如服务调用依赖、关联对象聚合等。包名代码模型中的包名对应领域对象所在的软件包。类名代码模型中的类名对应领域对象的类名。方法名代码模型中的方法名对应领域对象实现或操作的方法名。 在建立这种映射关系后就可以得到如下图的微服务代码结构了。
非典型领域模型
有些业务场景可能并不能如你所愿你可能无法设计出典型的领域模型。这类业务中有多个实体实体之间相互独立是松耦合的关系这些实体主要参与分析或者计算你找不出聚合根但就业务本身来说它们是高内聚的。而它们所组合的业务与其它聚合是在一个限界上下文内你也不大可能将它单独设计为一个微服务。这种业务场景其实很常见。比如在个人客户领域模型内有客户归并的聚合它扫描所有客户按照身份证号码、电话号码等是否重复的业务规则判断是否是重复的客户然后对重复的客户进行归并。这种业务场景你就找不到聚合根。那对于这类非典型模型我们还是可以借鉴聚合的思想仍然用聚合来定义这部分功能并采用与典型领域模型同样的分析方法建立实体的属性和方法对方法和服务进行封装和分层设计设计仓储建立领域对象之间的依赖关系。唯一可惜的就是我们依然找不到聚合根不过也没关系除了聚合根管理功能外我们还可以用 DDD 的其它设计方法。
你知道的越多你不知道的越多。