功能特性解耦和ff0000">高内聚性。避免一个类承担两个特性,修改A特性的时...">

设计原则与典型架构设计模型

架构的设计本质都是为了高内聚、低耦合

1. SOLID原则

1.1. S单一职责原则(single responsibility)

一个class应该只做一件事,一个class应该只有一个变化的原因,核心是<font color="#ff0000">功能特性解耦和<font color="#ff0000">高内聚性。避免一个类承担两个特性,修改A特性的时候导致B特性引入BUG。避免修复A问题,导致B问题修改的引入。

1.2. O开闭原则(open-close)

class 应该对扩展开放对修改关闭。<font color="#ff0000">避免增加新功能导致修改引入。

1.3. L里氏替换原则(Liskov Substitution Principle,LSP)

If S is a subtype of T, then objects of type T may be replaced with objects of type S, without breaking the program。 如果S是T的子类,则T的对象可以替换为S的对象,而不会破坏程序。

Functions that use pointers of references to base classes must be able to use objects of derived classes without knowing it。 所有引用其父类对象方法的地方,都可以透明的替换为其子类对象。

1.4. I接口隔离原则(interface Segregation)

隔离意味着保持独立,接口隔离原则是关于接口的独立。将一个万能的接口拆分成多个独立的接口,<font color="#ff0000">让子类可以选择性实现其中的部分接口。它反映了基类与子类之间的关系,是对开闭原则的补充,是对实现抽象化的具体步骤的规范。

[!note]
接口隔离原则(Interface Segregation Principle,ISP)的定义是客户端不应该依赖它不需要的接口,类间的依赖关系应该建立在最小的接口上。简单来说就是建立单一的接口,不要建立臃肿庞大的接口。也就是接口尽量细化,同时接口中的方法尽量少。使用接口隔离原则前首先需要满足单一职责原则。

1.5. D依赖倒置原则(Dependence Inversion)

我们的class应该<font color="#ff0000">依赖接口和抽象类,而不是具体的类和函数。实现可以变,接口不能变。

2. 设计原则

设计模式和SOLID原则大部分是

2.1. 迪米特法则

迪米特法则(Law of Demeter )又叫做最少知识原则,也就是说,一个对象应当对其他对象尽可能少的了解。

迪米特法则的目的在于降低类之间的耦合。由于每个类尽量减少对其他类的依赖,因此,很容易使得系统的功能模块功能独立,相互之间不存在(或很少有)依赖关系。

迪米特法则不希望类之间建立直接的联系。如果真的有需要建立联系,也希望能通过它的友元类来转达。因此,应用迪米特法则有可能造成的一个后果就是:系统中存在大量的中介类,这些类之所以存在完全是为了传递类之间的相互调用关系——这在<span style="background:#fff88f">一定程度上增加了系统的复杂度。

3. DDD分层架构实现

分层依赖原则,每层只能与位于其下方的层发生耦合,上层可以依赖下层,下层不能依赖上层。

[!note]
TCP/IP协议栈的设计也是基于这种分层设计的思想

image.png

3.1. 用户接口层

用户接口层负责向用户显示信息和解释用户指令。这里的用户可能是:用户、程序、自动化测试和批处理脚本等等。

3.2. 应用层

应用层是很薄的一层,理论上不应该有业务规则或逻辑,主要面向用例和流程相关的操作。但应用层又位于领域层之上,因为领域层包含多个聚合,所以它可以协调多个聚合的服务和领域对象完成服务编排和组合,协作完成业务操作。此外,应用层也是微服务之间交互的通道,它可以调用其它微服务的应用服务,完成微服务之间的服务<font color="#ff0000">组合和编排。

  • 负责服务的组合、编排和转发
  • 负责处理业务用例的执行顺序以及结果的拼装
  • 以粗粒度的服务通过API网关向前端发布
  • 进行安全认证、权限校验、事务控制、发送或订阅领域事件等

在设计和开发时,不要将本该放在领域层的业务逻辑放到应用层中实现。因为庞大的应用层会使领域模型失焦,时间一长你的微服务就会演化为传统的三层架构,业务逻辑会变得混乱。

3.3. 领域层

领域层的作用是实现企业核心业务逻辑,通过各种校验手段保证业务的正确性。领域层主要体现领域模型的业务能力,它用来表达业务概念、业务状态和业务规则。领域层包含聚合根、实体、值对象、领域服务等领域模型中的领域对象。

领域层中的实体会采用<font color="#ff0000">充血模型来实现所有与之相关的业务功能。当领域中的某些功能,单一实体(或者值对象)不能实现时,<font color="#ff0000">领域服务就会出马,它可以<font color="#ff0000">组合聚合内的多个实体(或者值对象),实现复杂的业务逻辑。

3.4. 基础层

基础层是贯穿所有层的,它的作用就是为其它各层提供通用的技术和基础服务,包括第三方工具、驱动、消息中间件、网关、文件、缓存以及数据库等。比较常见的功能还是提供数据库持久化。

基础层包含基础服务,它采用<font color="#ff0000">依赖倒置设计,封装基础资源服务,实现应用层、领域层与基础层的解耦,降低外部资源变化对应用的影响

[!note]
在传统架构设计中,由于上层应用对数据库的强耦合,很多公司在架构演进中最担忧的可能就是换数据库了,因为一旦更换数据库,就可能需要重写大部分的代码,这对应用来说是致命的。那采用依赖倒置的设计以后,应用层就可以通过解耦来保持独立的核心业务逻辑。当数据库变更时,我们只需要更换数据库基础服务就可以了,这样就将资源变更对应用的影响降到了最低。

image.png

4. CQRS(Query Command Responsibility Segregation)

对与业务查询场景比较多、比较复杂的情况下,采用Command和Query模型分离的设计,可以使业务上进行一些解耦。命令和查询模型某种程度上比较相似,CQRS的设计可能会导致系统过于复杂。

  • Query模型一般可以<span style="background:#fff88f">只包括两层,DB视图和用户视图,将数据查询结果对象映射为接口响应模型。专用于查询的模型可以与领域模型解耦与数据查询方式和业务展示结果挂钩
  • 业务的复杂性导致我们查看的数据结构和存储的数据结构并不一致,如将多条记录合并为一条或通过联表查询组合成新记录。
  • 可以通过从OLTP数据库同步数据到OLAP数据,以实现Command和Query的分离。
    image.png
    优势:
  1. 提供吞吐和时延 => 查询分离,OLAP数据库(HBASE大宽表)
  2. 提供多个查询视图,避免业务间互相影响
    缺点:
  3. 数据同步时延、一致性的复杂性
  4. 代码编写的额外成本和复杂性增加

5. 整洁架构(洋葱架构)

整洁架构的层就像洋葱片一样,它体现了分层的设计思想。在整洁架构里,同心圆代表应用软件的不同部分,从里到外依次是领域模型、领域服务、应用服务和最外围的容易变化的内容,比如用户界面和基础设施。

  1. 整洁架构最主要的原则是<font color="#ff0000">依赖原则,它定义了各层的依赖关系,越往里依赖越低,代码级别越高,越是核心能力 。外圆代码依赖只能指向内圆,内圆不需要知道外圆的任何情况。
  2. 每一层对<font color="#ff0000">外暴露接口,隐藏内部使用细节。在较深的层定义抽象接口,在最外层提供具体实现。可以保证我们专注于领域模型,而不必过多地担心实现细节。可以通过类似于Spring之类的<span style="background:#fff88f">依赖注入框架在运行时将接口和实现连接起来。
  3. <font color="#ff0000">关注点分离。应用被分为若干层,每一层都有不同的职责和关注点。
  4. 代码的<font color="#ff0000">可测性提高,可以单独每每一层构建测试用例
    image.png
  • 领域模型:实现领域内核心业务逻辑,它封装了企业级的业务规则。领域模型的主体是实体,一个实体可以是一个带方法的对象,也可以是一个数据结构和方法集合。
  • 领域服务:实现涉及<font color="#ff0000">多个实体的复杂业务逻辑。
  • 应用服务:实现与用户操作相关的服务组合与编排,它包含了应用特有的业务流程规则,封装和实现了系统所有用例。
  • 基础层:最外层主要提供适配的能力,适配能力分为主动适配和被动适配。
    1. 主动适配主要实现外部用户、网页、批处理和自动化测试等对内层业务逻辑访问适配。
    2. 被动适配主要是实现核心业务逻辑对基础资源访问的适配,比如数据库、缓存、文件系统和消息中间件等。

6. 六边形架构(端口适配器架构)

六边形架构的核心理念是:应用是通过端口与外部进行交互的 。我想这也是微服务架构下API网关盛行的主要原因吧。也就是说,在下图的六边形架构中,红圈内的核心业务逻辑(应用程序和领域模型)与外部资源(包括 APP、Web 应用以及数据库资源等)完全隔离,<font color="#ff0000">仅通过适配器进行交互。它解决了业务逻辑与用户界面的代码交错问题,很好地实现了前后端分离。六边形架构各层的依赖关系与整洁架构一样,都是由外向内依赖。
image.png
六边形架构将系统分为内六边形和外六边形两层,这两层的职能划分如下:

  • 红圈内的六边形实现应用的核心业务逻辑;
  • 外六边形完成外部应用、驱动和基础资源等的交互和访问,对前端应用以 API 主动适配的方式提供服务,对基础资源以依赖倒置被动适配的方式实现资源访问。
    六边形架构的一个端口可能对应多个外部系统,不同的外部系统也可能会使用不同的适配器,由适配器负责协议转换。这就使得应用程序能够以一致的方式被用户、程序、自动化测试和批处理脚本使用