这里写自定义目录标题
全局分析阶段输出的业务需求称为业务服务。业务服务满足了角色的服务请求,在解空间体现为服务与客户的协作关系,形成的协作接口称为契约。一个业务服务对应于脚骨映射阶段需要定义的服务契约。服务契约面向服务模型,它向客户端传递的消息数据称为消息契约。消息契约是组成服务契约的一部分。
消息契约对应上下文映射的发布语言模式,根据客户端发起对服务操作的类型,分为命令、查询和事件。
命令:是一个动作,要求其他服务完成某些操作,会改变系统的状态;
查询:是一个请求,查看是否发生了什么事情。没有副作用,不改变系统状态;
事件:既是事实又是触发器,用通知的方式向外部表明发生了某些事。
常见的协作模式:请求/响应模式、即发即忘模式、发布/订阅模式。
查询采用请求/响应模式;命令操作如果需要返回操作结果,需选择请求/响应模式,否则可以选择即发即忘模式。
消息契约模型
对于请求消息,建议以“动名词+Request”的形式命名,例如QueryingDeviceRequest。
对于响应消息,建议视图模型以Presentation或View为后缀,
数据契约以Response为后缀,
命令结果以Result为后缀。
消息契约模型定义在限界上下文的外部网关层,它的引入是为了保护领域模型。对于远程服务而言,为它定义消息契约模型,运用了数据传输对象模式(DTO)。
远程服务直接调用领域模型的坏处:
通信机制:领域模型对象在进程内传递,无须序列化和反序列化。为了支持分布式通信,需要让领域模型对象支持序列化,这就造成了对领域模型的污染。
安全因素:领域驱动设计提倡避免贫血模型,且多数领域实体对象并非不可变的值对象。若直接暴露给外部服务,调用者可能会绕过服务方法直接调用领域对象封装的行为,或者通过set方法修改其数据。
变化隔离:若将领域对象直接暴露,就可能受到外部调用请求变化的影响。领域逻辑与外部调用的变化方向往往不一致,需要一层间接的对象来隔离这种变化。
消息契约的转换
领域模型对象与契约对象之间的转换应基于信息专家模式,优先考虑将转换行为分配给消息契约对象,因为它最了解自己的数据结构。领域模型对象位于限界上下文内部领域层,遵循整洁架构思想,它不应该知道消息契约对象。
转换行为分为两个方向
一个方向是将消息契约对象转换为领域模型对象。由于消息契约对象将自身实例转换为领域模型对象,故而定义为实例方法。
public class QueryingDeviceRequest implements Serizable{
public Device toDevice(){}
}
另一个方向是将领域模型对象转换为消息契约对象。由于消息契约对象的实例还没有创建,故而定义为静态方法。
public class DeviceResponse implements serializable {
public static DeviceResponse from(Device device) {}
}
领域模型对象往往以聚合为单位,聚合的设计原则要求聚合之间通过根实体的ID进行关联,如果消息契约需要组装多个聚合,又未提供聚合的信息,就需要求助于南向网关的端口访问外部资源。为了避免消息契约对象依赖南向网关的端口,最好由专门的装配器队形负责消息契约对象的装配。
public class DeviceResponseAssembler{
}
有的设计实践将消息契约与抽象的服务契约接口放在一个单独的JAR包中,此时的消息契约就不能依赖领域模型,则可以考虑在应用服务层引入专门的装配器对象。
消息契约模型与领域模型的转换不属于领域逻辑的一部分,因而一定要注意维护好菱形对称架构中内部领域层与外部网关层的边界。
服务契约
领域驱动设计的服务契约对应上下文映射的开放主机服务模式,通常指采用分布式通信的远程服务。如果不采用跨进行通信,则应用服务也可以认为是服务契约,与远程服务共同组成菱形对称架构的北向网关。
应用服务
在领域层与用户界面层之间引入了应用层,应用层要尽量简单,不包含业务规则或知识,而只为下一层(领域层)中的领域对象协调任务,分配工作,使他们互相协作。若采用对象建模范式,遵循面向对象的设计原则,应尽可能为领域层定义细粒度的领域模型对象。细粒度设计不利于它的客户端调用,基于KISS原则或最小知识原则,希望调用者了解的只是越少越好,调用越简单越好,这就需要引入一个间接层来封装。这就是应用层存在的主要意义。
应用服务设计的准则
- 不包含领域逻辑的业务服务应该被定义为应用服务。
应用层定义的内容主要为应用服务,它是外观模式的体现,即为子系统中的一组接口提供一个一致的界面,外观模式定义了一个高层接口,这个接口是的这一个字系统更加容易使用。
外观模式的场景:
要为一个复杂子系统提供一个简单接口
当客户程序与抽象类的实现部分之间存在着很大的依赖性
需要构建一个层次结构的子系统时,使用外观模式定义子系统中每层的入口点
对外应用服务为外部调用者提供了一个简单统一的接口,该接口为一个完整的业务服务提供了自给自足的功能,使得调用者无须求助于别的接口就能满足服务请求;对内,应用服务自身并不包含任何领域逻辑,仅负责协调领域模型对象,通过其领域能力组合完成一个完整的应用目标。应用服务是调用领域层的入口点,通过它降低客户程序与领域层之间的依赖,自身不应该包含任何领域逻辑。
2.与横切关注点协作的服务应被定义为应用服务。
消息验证
错误处理
监控
事务
认证与授权
远程服务
服务资源契约:面向资源的服务建模思想驱动,根据调用者的不同分为资源服务和控制服务。
服务行为契约:面向行为的服务建模思想驱动,采用了面向服务架构的概念模型,被定义为提供者服务。
服务事件契约:面向事件的服务建模思想驱动,消费者反而成为了限界上下文的开放主机服务,即订阅服务。
服务资源契约
面向资源的服务建模思想,遵循REST架构风格,从资源的角度思考服务设计。
如果服务资源面向下游限界上下文,可以将该服务以“<资源名>+Resource”格式命名,例如DeviceResource。
如果服务资源面向前端UI,可以遵循模型-视图-控制器(MVC)模式,资源就是模型,服务为控制器,以"<模型名>+Controller"格式命名,例如DeviceController。
无论是资源还是模型,结合领域驱动设计,都可以映射为领域模型中的聚合,即以聚合根实体为入口,将聚合内的领域模型当资源。
一个REST风格服务实际上是对客户端与资源之间交互协作的抽象,利用了关注点分离原则分离了资源、访问资源的动作和表述资源的形式。资源作为名词,是对一组领域概念的映射;动词是在资源上执行的动作。服务端在执行完该动词后,返回给客户端的内容则以某种表述形式呈现,它们共同组成了一个完整的服务资源契约。
服务行为契约
服务行为的调用者可以认为是服务消费者,提供服务行为的对象则是服务提供者。
以服务行为驱动服务契约的定义,需要根据消费者与提供者之间的协作关系确定。消费者发起服务请求,提供者履行职责并返回结果,构成了服务行为契约。
契约式设计对消费者和提供者两方的协作进行了约束,作为请求方的消费者,需要定义发起请求的必要条件,这就是服务行为的输入参数,在契约式设计中被称为前置条件;作为响应方的提供者,需要阐明服务必须对消费者做出保证的条件,在契约式设计中被称为后置条件。前置条件和后置条件组成了服务行为契约的消息契约模型。
要保证服务接口的易用性,应遵循最小知识法则,让消费者对提供者尽可能少地了解,降低调用的复杂度。从契约的角度讲,就是将服务消费者承担的医务降到最少,让服务消费者提供适量的信息即可。
在定义服务行为模型时,可以问以下几个问题:
假如服务行为已经存在,它的前置条件和后置条件应该是什么
服务消费者应该承担的最小义务包括哪些,而它又应该享有什么样的权利
该用什么样的名字才能表达服务行为的价值;
服务时间契约
倘若客户端与服务端协作双方不再关注服务的行为,也无须操作服务资源,而是就状态变更触发的事件达成协作契约。既然契约就是事件,意味着发布者与订阅者之间的耦合仅限于事件。发布者不需要知道究竟有哪些限界上下文需要订阅该事件,只需要按照自己的心意,在业务状态发生变更时发布事件;订阅方也不需要关心它锁订阅的事件究竟来自何方。
事件存在两种不同的定义风格:事件通知和事件携带状态迁移。
采用事件通知定义的事件不会传递整个领域模型对象,而是仅携带该领域模型对象的身份标识。需要通过ID调用发布者所在限界上下文的远程服务获取更多的属性。
事件携带状态迁移的定义风格将事件定义为一个自给自足的对象,是发布者与订阅者协商的结果,且只满足该事件参与协作的业务场景,并不一定要求传递整个领域模型对象。
为了区分事件的作用范围,将领域层发布的事件称为领域事件,属于领域模型设计要素定义在菱形对称架构的内部领域层;将应用服务发布的事件称为应用事件,通常定义在外部网关层。
领域事件通常用于聚合之间的协作,或者作为事件溯源模式操作的对象。应用事件才是服务事件契约的组成部分,如果领域事件也需要穿越限界上下文的边界,就要保证领域事件爱你的稳定性,这一要求与对实体、值对象的要求完全一致。为了确保限界上下文的自治性,可以考虑将领域事件转换为应用事件。
一个定义良好的应用事件应具备如下特征:
事件属性应以基本类型为主,保证事件的平台中立性,减少甚至消除对领域模型的依赖。
发布者的聚合ID作为构成应用事件的主要内容。
保证应用事件属性的最小集
为应用事件定义版本号,支持应用事件的版本管理
为应用事件定义唯一的ID
为应用事件定义创建时间戳,支持对事件的按序处理
应用事件应是不变的对象。
设计服务契约
倘若限界上下文采用菱形对称架构,则限界上下文之间、前端与限界上下文之间以及限界上下文与伴生系统之间的协作都将通过北向网关与南向网关进行。
设计服务契约,实则是要定义限界上下文远程服务或应用服务的服务契约。倘若目标系统的系统分层架构引入了边缘层,在定义服务契约时,还需要从UI的角度思考控制器远程服务的契约定义。
在限界上下文边界内,远程服务与应用服务的服务方法通常形成一对一的映射关系。他们都作为角色构造型满足客户端向目标系统发起的服务请求,提供服务价值。如此一来,远程服务或应用服务的服务方法就会作为服务驱动设计的唯一入口点,服务方法履行的职责就是全局分析阶段获得的业务服务。
业务服务细化
一个业务服务有可能需要多个限界上下文共同协作,要设计服务契约,就应该围绕着业务服务开展。
设计服务契约时,需要区分一下概念:
公开给UI前端或外部调用者的服务契约;
公开给下游限界上下文的服务契约。
设计服务契约时,无须考虑领域模型对象,只需要考虑:
面向UI的控制器服务
面向第三方调用或下游限界上下文的资源服务
面向第三方调用或下游限界上下文的供应者服务
面向下游限界上下文的应用服务
发生在发布者与订阅者之间的应用事件
作为发布语言的消息契约。
设计服务契约的前提是已经识别出目标系统的限界上下文。当开始针对业务服务进行梳理时,可以抹去领域逻辑的细节,重点关注
哪一个限界上下文(或边缘层)公开服务,以相应角色的服务请求;
哪些限界上下文参与了业务服务的执行,定义了什么样的服务。
为了弄清楚参与服务的协作方式,需要为业务服务编写业务服务规约。
服务序列图
限界上下文作为序列图的参与对象,发出的消息实则就是我们要识别的服务契约,而消息的传递,也代表了限界上下文之间的协作。如果执行步骤还需要与目标系统之外的伴生系统产生协作,则伴生系统也将作为序列图的参与对象。将由伴生系统与限界上下文参与的序列图称为服务序列图。
服务契约的表示
欢迎使用Markdown编辑器
你好! 这是你第一次使用 Markdown编辑器 所展示的欢迎页。如果你想学习如何使用Markdown编辑器, 可以仔细阅读这篇文章,了解一下Markdown的基本语法知识。
新的改变
我们对Markdown编辑器进行了一些功能拓展与语法支持,除了标准的Markdown编辑器功能,我们增加了如下几点新功能,帮助你用它写博客:
- 全新的界面设计 ,将会带来全新的写作体验;
- 在创作中心设置你喜爱的代码高亮样式,Markdown 将代码片显示选择的高亮样式 进行展示;
- 增加了 图片拖拽 功能,你可以将本地的图片直接拖拽到编辑区域直接展示;
- 全新的 KaTeX数学公式 语法;
- 增加了支持甘特图的mermaid语法1 功能;
- 增加了 多屏幕编辑 Markdown文章功能;
- 增加了 焦点写作模式、预览模式、简洁写作模式、左右区域同步滚轮设置 等功能,功能按钮位于编辑区域与预览区域中间;
- 增加了 检查列表 功能。
功能快捷键
撤销:Ctrl/Command + Z
重做:Ctrl/Command + Y
加粗:Ctrl/Command + B
斜体:Ctrl/Command + I
标题:Ctrl/Command + Shift + H
无序列表:Ctrl/Command + Shift + U
有序列表:Ctrl/Command + Shift + O
检查列表:Ctrl/Command + Shift + C
插入代码:Ctrl/Command + Shift + K
插入链接:Ctrl/Command + Shift + L
插入图片:Ctrl/Command + Shift + G
查找:Ctrl/Command + F
替换:Ctrl/Command + G
合理的创建标题,有助于目录的生成
直接输入1次#,并按下space后,将生成1级标题。
输入2次#,并按下space后,将生成2级标题。
以此类推,我们支持6级标题。有助于使用TOC
语法后生成一个完美的目录。
如何改变文本的样式
强调文本 强调文本
加粗文本 加粗文本
标记文本
删除文本
引用文本
H2O is是液体。
210 运算结果是 1024.
插入链接与图片
链接: link.
图片:
带尺寸的图片:
居中的图片:
居中并且带尺寸的图片:
当然,我们为了让用户更加便捷,我们增加了图片拖拽功能。
如何插入一段漂亮的代码片
去博客设置页面,选择一款你喜欢的代码片高亮样式,下面展示同样高亮的 代码片
.
// An highlighted block
var foo = 'bar';
生成一个适合你的列表
- 项目
- 项目
- 项目
- 项目
- 项目1
- 项目2
- 项目3
- 计划任务
- 完成任务
创建一个表格
一个简单的表格是这么创建的:
项目 | Value |
---|---|
电脑 | $1600 |
手机 | $12 |
导管 | $1 |
设定内容居中、居左、居右
使用:---------:
居中
使用:----------
居左
使用----------:
居右
第一列 | 第二列 | 第三列 |
---|---|---|
第一列文本居中 | 第二列文本居右 | 第三列文本居左 |
SmartyPants
SmartyPants将ASCII标点字符转换为“智能”印刷标点HTML实体。例如:
TYPE | ASCII | HTML |
---|---|---|
Single backticks | 'Isn't this fun?' |
‘Isn’t this fun?’ |
Quotes | "Isn't this fun?" |
“Isn’t this fun?” |
Dashes | -- is en-dash, --- is em-dash |
– is en-dash, — is em-dash |
创建一个自定义列表
-
Markdown
- Text-to- HTML conversion tool Authors
- John
- Luke
如何创建一个注脚
一个具有注脚的文本。2
注释也是必不可少的
Markdown将文本转换为 HTML。
KaTeX数学公式
您可以使用渲染LaTeX数学表达式 KaTeX:
Gamma公式展示 Γ ( n ) = ( n − 1 ) ! ∀ n ∈ N \Gamma(n) = (n-1)!\quad\forall n\in\mathbb N Γ(n