架构设计系列之常见架构(一)

本部分对常见架构进行简单的说明。

一、三层架构之经典 MVC

经典的 MVC 架构(Model-View-Controller)架构是软件系统架构设计中的经典,它将应用程序分为三个主要部分:

  • 模型(Model)
  • 视图(View)
  • 控制器(Controller)

这样的三层架构有助于实现业务逻辑的分离,提高代码的可维护性和可扩展性。

二、 CQRS(命令查询职责分离)

命令查询职责分离模式(Command Query Responsibility Segregation,CQRS)是一种软件架构模式,它通过从业务上分离修改(Command:增、删、改,会对系统状态进行修改)和查询(Query:查,不会对系统状态进行修改)的行为,使逻辑清晰,提高系统的可维护性和灵活性。

1 、优点

  • 业务逻辑清晰:将修改和查询操作分开,使业务逻辑更加清晰。命令负责修改状态,而查询负责获取信息,降低系统复杂性
  • 可维护性增强:通过将写模型和读模型分离,可以独立演化和优化两者。提高了系统的可维护性,开发人员可以更容易地理解和修改两个模型
  • 扩展性:支持根据系统需求独立扩展命令和查询部分,这种灵活性使得系统更容易适应不断变化的需求
  • 更好的性能优化:通过专门优化读模型,可以更好地满足查询性能的需求,有助于提高系统的整体性能

2 、不足

  • 结构复杂:引入两个独立的模型(读写),使得系统结构复杂度高,维护和理解这两个模型之间的关系可能需要更多的工作
  • 冗余代码:由于存在独立的读写模型,可能导致代码冗余,特别是对于一些共享的业务逻辑,这需要谨慎的设计和维护,以避免冗余
  • 性能问题:涉及多次数据库操作,可能导致性能问题,特别是在需要频繁进行读写操作的情况下,需要根据具体情况进行性能优化
  • 工作流不直观:将任务分解为多个步骤,可能导致工作流难以理解,尤其是对于新加入的开发人员,文档和培训对于确保团队对工作流的理解至关重要
  • 缺乏标准化:并没有广泛的标准,团队在实践中需要根据自身需求进行调整,可能缺乏一致性和规范性

3 、总结

CQRS 是一个特定场景下有益的架构模式,但在引入时需要仔细权衡其优缺点。在对系统的可维护性、可扩展性和性能有较高要求的情况下,CQRS 可能是一个有价值的选择。然而,对于简单的应用程序,引入 CQRS 可能会增加不必要的复杂性。在实践中,团队应该根据具体情况慎重考虑是否采用 CQRS 。

三、六边形架构

六边形架构(Hexagonal Architecture)也称为端口适配器模式,是 Alistair Cockburn 在 2005 年首次提出的一种软件架构模式。其主要目标是将应用程序的核心逻辑与特定的输入/输出技术解耦,使其能够更灵活的应对变化和演化。

1 、三个原则

明确分层层次(Explicitly separate Application,Domain,and Infrastructure)

在六边形架构中,明确分离应用程序(Application)、领域(Domain)和基础设施(Infrastructure)是关键的设计原则,这种分离使开发者将关注点分离开,每一层都可以独立变化而不影响其他层,提高了系统的可维护性、可测试性和可扩展性。

  • 应用程序层(Application Layer)
    • 责任:包含应用程序的业务逻辑,负责协调领域层和基础设施层的交互,不包含具体的业务规则,而是将请求委托给领域层进行处理
    • 实现:通常由应用服务组成,提供用例的实现,负责接收外部请求、处理输入数据、协调领域层的操作,并调用适当的基础设施服务
  • 领域层(Domain Layer)
    • 责任:包含系统的核心业务逻辑和领域模型,这是系统的灵魂,包含了问题域的概念、规则和约束
    • 实现:由实体(Entities)、值对象(Value Objects)、聚合(Aggregates)、领域服务(Domain Services)等构成,协调工作,实现业务规则,确保系统的行为符合领域的要求
  • 基础设施层(Infrastructure Layer)
    • 责任:负责处理与外部系统的通信、数据库访问、日志记录等与具体技术相关的事务,包含所有与技术实现有关的组件
    • 实现 :包括数据库访问层、外部服务通信层、日志记录、配置等,这些组件对系统的业务逻辑是透明的,通过接口与应用程序层和领域层进行交互

依赖关系指向领域层(Dependencies are going from Application and infrastructure to the Domain)

确保领域层保持独立性,不依赖于具体的应用程序逻辑或基础设施技术,提高系统的可测试性、可维护性和可扩展性。

技术上,就是 Application 和 Infrastructure 都不能直接互相调用对方的功能或者操作,只有经过 Domain 的接口才能沟通,确保 Domain 部分具有完整的独立性,不受 Application 和 Infrastructure 变更的影响,从而保持稳定,这样的代码结构易读、易管理、易维护。

  • 依赖关系的方向
    • 应用程序层向领域层的依赖:应用程序层包含用例的实现,负责协调系统的操作并调用领域层的服务
    • 基础设施层向领域层的依赖:基础设施层包含与技术实现相关的组件,领域层不应该直接依赖于这些具体的技术实现,而是通过接口定义领域层所需的服务,并由基础设施层来实现这些接口
  • 实现方式
    • 领域服务接口:在领域层中定义接口,描述领域服务的行为,这些接口是应用程序层和基础设施层依赖的抽象 ➡️ 如果领域层需要使用某种外部服务,可以在领域层定义一个接口,然后在基础设施层中实现这个接口
    • 依赖反转:通过依赖反转原则,应用程序层和基础设施层不直接依赖于领域层的具体实现,而是依赖于领域层定义的接口和抽象,这会让领域层能独立于其他层进行演化,不受具体实现细节的影响
    • 测试驱动开发:将依赖关系的方向设计成从应用程序和基础设施指向领域,有助于采用 TDD,通过在应用程序层和基础设施层编写测试用例,并通过模拟或替代领域层的具体实现,可以更容易进行单元测试,确保领域层的正确性

使用端口和适配器隔离边界(We isolate the boundaries by using Ports and Adapters)

六边形架构使用端口和适配器模式来隔离系统的边界,以提高系统的可测试性、可维护性和灵活性,目标是将业务逻辑与外部环境解耦,让系统的各个部分更容易替换、测试和理解

  • 基本概念
    • 端口:定义系统与外界通信的接口,表示系统的一种能力或服务,通常通过接口来表示,定义系统对外提供的服务,不关心具体的实现,只关注服务的契约
    • 适配器:连接系统内部和外部的组件,负责将系统内的数据结构或接口转换成外部系统期望的形式,是外部环境和系统内部通信的桥梁,确保系统的核心业务逻辑不受业务环境的影响
  • 具体应用
    • 内部端口和适配器:将应用程序划分为核心业务逻辑(Application)和外部环境(Infrastructure)两部分,内部端口表示系统对外部环境提供的服务,而内部适配器则负责将内部数据结构适应外部环境的需求
    • 外部端口和适配器:外部端口表示系统对外部环境的依赖,而外部适配器则将外部环境的服务适配成系统内部期望的形式,使系统的核心业务逻辑不直接依赖于具体的外部实现,而是通过端口和适配器与外部环境进行通信

2 、特点

  • 对称性:系统的设计围绕着一个中心的应用核心组件,所有的交互都必须通过这个中心
  • 隔离性:应用程序的核心组件被一层薄的适配器包围,使得它对外部环境的变化免疫
  • 可插拔性:系统可以通过改变其适配器来更改接口,并适应不同的上下文

3 、组成部分

  • 应用核心:整个架构的心脏,包含了应用程序的业务逻辑和领域模型,不依赖任何特定的外部元素,只关注应用程序的核心功能
  • 端口:是应用程序核心向外提供的接口,定义了应用程序如何与外部世界进行通信
  • 适配器:用于连接应用程序核心和外部世界的栋梁,实现了端口的具体行为,并将请求路由到正确的位置

4 、好处

  • 灵活性:当外部环境发生变化时,只需要修改适配器即可,而无需触及应用程序的核心
  • 测试友好:可以轻松模拟和替换适配器,从而更容易测试应用程序的核心部分
  • 低耦合:应用程序的核心部分与外部环境完全解耦,使其更易于维护和扩展

5 、不足

  • 设计复杂度高
  • 需要花费更多时间进行需求分析和设计
  • 学习曲线比较陡峭,需要具备一定的软件设计知识

6 、总结

六边形架构是一种有助于提高代码代码质量和维护性的设计方式,但它也有一定的学习成本和实施难度。在实际应用中,可以根据具体项目的规模和复杂程度以及团队的技术能力,灵活运用此模式。

四、洋葱架构

洋葱架构(Onion Architecture)是由 2008 年,Jeffrey Palermo 提出,它在端口和适配器架构的基础上将领域放在应用中心,将用户用例和基础设施放在外围,这种设计思路类似于六边形架构,都是通过适配器代码将应用核心从对基础设施的关注中解放出来,以避免基础设施代码渗透到应用核心之中,使得框架和中间件需要改变替换的时候更加轻松,不会影响到核心领域。

1 、设计原则

  • 依赖性:洋葱架构中的圆圈代表不同的责任层,进入越深越接近领域和业务规则,外圈代表机制,内圈代表核心领域逻辑,外层依赖于内层,而内层对外圈一无所知
  • 数据封装:每个圈层封装内部实现细节,向外层公开接口,在内层定义抽象接口,在外层提供具体实现,确保专注于领域模型,而不必过多地担心实现细节。运行时,可以使用依赖注入框架,将接口和实现连接起来
  • 关注点分离:应用系统被分为多个层级,每一个层级都有一组职责,并解决不同的关注点
  • 耦合性:低耦合性,一个模块和另一个模块交互时不需要关注另一个模块的内部具体实现,所有的内部层级不需要关注外部层级的具体实现

2 、架构分层

  • 应用服务层:负责协调请求步骤的服务,不应该有任何业务逻辑,应用服务与其他服务交互来满足客户请求
  • 领域服务层:负责保持领域逻辑和业务规则,所有的业务逻辑应该作为领域服务的一部分来实现。领域服务由应用服务协调,服务于业务用例。不是简单的 CRUD 服务
  • 领域模型层:封装属性和实体行为
  • 基础设施层:在洋葱架构中的最外层,负责与外部世界交互,不解决任何领域的问题,没有任何逻辑
  • 可观察性服务层:负责监控应用,可以用于数据收集(指标、日志、痕迹)、数据存储、可视化等

3 、优势

洋葱架构建立在一个领域模型上,各层之间通过接口交互,其设计思想是在领域实体和业务规则构成架构的核心部分时,尽可能将外部依赖性保持在外:

  • 提供灵活、可持续和可移植的架构
  • 各层之间没有紧密耦合,且有关注点的分离
  • 所有代码都依赖更深的层或者中心,提高可维护性
  • 提高整体代码的可测试性,单元测试可以在单独的层创建,不会影响其他的模块
  • 框架/技术可以容易改变而不影响核心领域

4 、不足

  • 设计复杂性:多个端口和适配器需要额外的设计工作且增加了系统复杂度
  • 维护困难:洋葱架构的系统非常复杂对应的维护难度也比较高

5 、总结

洋葱架构适用于大型、复杂的应用程序,对于需要长期维护和演进的系统,其设计理念有助于降低变更的风险,提高系统的可靠性和可扩展性,在具体应用时,可以根据项目规模和团队技术水平做出适当的调整。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/222701.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

智能优化算法应用:基于差分进化算法3D无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用:基于差分进化算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用:基于差分进化算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.差分进化算法4.实验参数设定5.算法结果6.…

DC-3靶场

DC-3 DC-3靶场链接:https://download.vulnhub.com/dc/DC-3-2.zip 下载后解压会有一个DC-3.ova文件,直接在vm虚拟机点击左上角打开-->文件--.选中这个.ova文件就能创建靶场,kali和靶机都调整至NAT模式 首先进行主机发现: arp…

基于java的医院住院管理系统的设计与实现论文

摘 要 互联网发展至今,无论是其理论还是技术都已经成熟,而且它广泛参与在社会中的方方面面。它让信息都可以通过网络传播,搭配信息管理工具可以很好地为人们提供服务。针对医院住院信息管理混乱,出错率高,信息安全性差…

Vue学习笔记-Vue3中的customRef

作用 创建一个自定义的ref&#xff0c;并对其依赖项的更新和触发进行显式控制 案例 描述&#xff1a;向输入框中输入内容&#xff0c;在下方延迟1秒展示输入内容 代码&#xff1a; <template><input type"text" v-model"keyword"><h3&…

网络安全项目实战(四)--报文检测

8. TCP/UDP 段 目标 了解 TCP 段头的组织结构了解 UDP 段头的组织结构掌握 TCP/UDP 段的解析方式 8.1. UDP 段格式 下图是UDP的段格式&#xff08;该图出自[TCPIP]&#xff09;。 8.2. UDP头部 //UDP头部&#xff0c;总长度8字节// /usr/include/linux/udp.h struct udphdr …

自定义Axure元件库及原型图泳道图的绘制(详细不同类的案例)

目录 前言 一.自定义元件库 1.1 自定义元件库的作用 1.2 自定义元件的操作 二.流程图 2.1 流程图的作用 2.2 绘制流程图 2.3 简易流程图案例 三.泳道图 3.1 泳道图的作用 3.2 流程图和泳道图的区别 3.3 绘制泳道图 四.绘制前的准备 五.案例 4.1 门诊模块案例 4.2 …

聚观早报 |iOS17.3引入设备被盗保护;iPhone16或调整设计

【聚观365】12月14日消息 iOS17.3引入设备被盗保护 iPhone16或调整设计 马斯克星链网络使用量飙升 华为鸿蒙智行App正式上线 特斯拉人形机器人Optimus二代上线 iOS17.3引入设备被盗保护 苹果向iPhone用户推送了iOS17.3开发者预览版Beta更新&#xff0c;本次更新距离上次发…

Vue2.x源码:new Vue()做了啥

例子1new Vue做了啥?new Vue做了啥,源码解析 initMixin函数 初始化 – 初始化Vue实例的配置initLifecycle函数 – 初始化生命周期钩子函数initEvents – 初始化事件系统初始化渲染 initRender初始化inject选项 例子1 <div id"app"><div class"home&…

docker安装最新版SQL Server并还原备份的数据库

docker安装数据库 拉取微软官方最新版镜像 docker pull mcr.microsoft.com/mssql/server 拉去镜像并创建容器 docker run -e "ACCEPT_EULAY" -e "SA_PASSWORDsa_password_123456" -p 1433:1433 -v /opt/:/opt --name sqlserver -d mcr.microsoft.com/ms…

前端页面显示的时间格式为:2022-03-18T01:46:08.000+00:00 如何转换为:年-月-日,并根据当前时间判断为几天前

由于后端每条博文的发表时间是以“xxxx—xx—xxxx:xx:xx”的形式显示的&#xff0c; 现在要在前端改成“xxxx年xx月xx日”的形式。 并对10分钟内发表的显示“刚刚”&#xff0c;对24小时内发表的显示“小时前”。 超过24小时&#xff0c;小于48小时&#xff0c;显示“1天前”。…

生产实践:基于K8S的私有化部署解决方案

随着国内数字化转型的加速和国产化进程推动&#xff0c;软件系统的私有化部署已经成为非常热门的话题&#xff0c;因为私有化部署赋予了企业更大的灵活和控制权&#xff0c;使其可以根据自身需求和安全要求定制和管理软件系统。下面分享下我们的基于k8S私有化部署经验。 私有化…

Nginx 服务器安装及配置文件详解

1. 安装nginx 1.1 选择稳定版本 我们编译安装nginx来定制自己的模块&#xff0c;机器CentOS 6.2 x86_64。首先安装缺少的依赖包&#xff1a; # yum -y install gcc gcc-c make libtool zlib zlib-devel openssl openssl-devel pcre pcre-devel 这些软件包如果yum上没有的话…

VS2022配置C++ 20解决import std报错

C 20新特征支持用import std来导入std模块&#xff0c;如下&#xff1a; 配置时主要有两个步骤&#xff1a; &#xff08;1&#xff09;项目--属性--常规--C语言标准--预览 - 最新 C 工作草案中的功能 (/std:clatest) 注意选择ISO C20 标准 (/std:c20)也不能正常使用&#xf…

【PgSQL】导出表结构为EXCEL

详细SQL语句&#xff1a; C.relname ‘你的表名’ 直接输入表面即可 PgSQL 打印表结构语句 SELECT C.relname AS "表名",CAST(obj_description(C.oid, pg_class) AS VARCHAR) AS "表名描述",A.attname AS "字段名",CASE WHEN A.attnotnull f …

(C++)无重复字符的最长子串--滑动窗口

个人主页&#xff1a;Lei宝啊 愿所有美好如期而遇 力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台备战技术面试&#xff1f;力扣提供海量技术面试资源&#xff0c;帮助你高效提升编程技能&#xff0c;轻松拿下世界 IT 名企 Dream Offer。https://le…

Oracle存储过程打印输出错误信息、行号,快速排查

测试存储过程如下&#xff1a; create or replace procedure prc_test isp_1 varchar2(2); beginp_1 : lxw测试;exceptionwhen others thendbms_output.put_line(sqlcode); --Oracle内置变量&#xff0c;错误代码dbms_output.put_line(sqlerrm); --Oracle内置变量&#xff0c;…

【SpringBoot篇】基于布隆过滤器,缓存空值,解决缓存穿透问题 (商铺查询时可用)

文章目录 &#x1f354;什么是缓存穿透&#x1f384;解决办法⭐缓存空值处理&#x1f388;优点&#x1f388;缺点&#x1f38d;代码实现 ⭐布隆过滤器&#x1f38d;代码实现 &#x1f354;什么是缓存穿透 缓存穿透是指在使用缓存机制时&#xff0c;大量的请求无法从缓存中获取…

KylinV10 将项目上传至 Github

KylinV10 将项目上传至 Github 银河麒麟操作系统 V10 是在 Ubuntu 的基础上开发的&#xff0c;所以适用于 Ubuntu 的也适用于 KylinV10 一般上传至 GitHub&#xff0c;有两种方式&#xff0c;一种是 HTTPS&#xff0c;一种是 SSH&#xff0c;但是在 KylinV10 操作系统 HTTPS 的…

Android camera的metadata

一、实现 先看一下metadata内部是什么样子&#xff1a; 可以看出&#xff0c;metadata 内部是一块连续的内存空间。 其内存分布大致可概括为&#xff1a; 区域一 &#xff1a;存 camera_metadata_t 结构体定义&#xff0c;占用内存 96 Byte 区域二 &#xff1a;保留区&#x…

单机环境下一人一单

优惠券秒杀 添加优惠卷 店铺发布优惠券又分为平价券和特价券, 平价券可以任意购买而特价券需要秒杀抢购(限制数量和时间) tb_voucher(平价券): 优惠券的基本信息 tb_seckill_voucher(秒杀券): 有voucher_id字段表示具有优惠卷的基本信息,此外还有库存,开始抢购时间,结束抢购…