当前位置: 首页 > news >正文

「 系统设计 」 为什么要做架构分层?

「 系统设计 」 为什么要做架构分层?

参考&鸣谢

3.设计模式之分层思维:为什么要做代码分层架构?

从零开始学架构(八)分层架构和设计模式

架构模式之分层架构总结


文章目录

  • 「 系统设计 」 为什么要做架构分层?
    • 一、什么是分层架构
      • MVC
      • OSI
      • TCP/IP
      • 文件系统
    • 二、分层有什么好处
      • 模块化
      • 复用性
      • 拓展性
    • 三、如何来做系统分层
      • 确定层次
      • 定义接口
      • 遵循设计原则
    • 四、分层架构的不足
      • 复杂性问题
      • 性能问题
      • 灵活性问题
    • 五、回顾&小结

引言

在软件系统设计中,分层架构是一种常见而强大的设计模式。通过将系统划分为不同的层次,每个层次专注于特定功能,分层架构有助于提高系统的可维护性、可扩展性和模块化。本文将深入探讨分层架构的底层原理,阐述其优势以及一些可能的缺陷。

一、什么是分层架构

分层架构是一种将系统划分为多个层次的设计模式,每个层次专注于特定的功能。这样的设计使得系统的不同部分能够更好地组织和管理,从而提高了系统的可维护性、可扩展性和可理解性。

MVC

我们在刚刚成为程序员的时候,会被“教育”说系统的设计要是“MVC”(Model-View-Controller)架构。它将整体的系统分成了 Model(模型),View(视图)和 Controller(控制器)三个层次,也就是将用户视图和业务处理隔离开,并且通过控制器连接起来,很好地实现了表现和逻辑的解耦,是一种标准的软件分层架构。

img

另外一种常见的分层方式是将整体架构分为表现层、逻辑层和数据访问层:

  • 表现层,顾名思义嘛,就是展示数据结果和接受用户指令的,是最靠近用户的一层;
  • 逻辑层里面有复杂业务的具体实现;
  • 数据访问层则是主要处理和存储之间的交互。

这是在架构上最简单的一种分层方式。其实,我们在不经意间已经按照三层架构来做系统分层设计了,比如在构建项目的时候,我们通常会建立三个目录:Web、Service 和 Dao,它们分别对应了表现层、逻辑层还有数据访问层

img

OSI

除此之外,如果我们稍加留意,就可以发现很多的分层的例子。比如我们在大学中学到的 OSI 网络模型,它把整个网络分了七层,自下而上分别是物理层、数据链路层、网络层、传输层、会话层、表示层和应用层。

TCP/IP

工作中经常能用到 TCP/IP 协议,它把网络简化成了四层,即链路层、网络层、传输层和应用层。每一层各司其职又互相帮助,网络层负责端到端的寻址和建立连接,传输层负责端到端的数据传输等,同时呢相邻两层还会有数据的交互。这样可以隔离关注点,让不同的层专注做不同的事情。

img

文件系统

Linux 文件系统也是分层设计的,从下图你可以清晰地看出文件系统的层次。在文件系统的最上层是虚拟文件系统(VFS),用来屏蔽不同的文件系统之间的差异,提供统一的系统调用接口。虚拟文件系统的下层是 Ext3、Ext4 等各种文件系统,再向下是为了屏蔽不同硬件设备的实现细节,我们抽象出来的单独的一层——通用块设备层,然后就是不同类型的磁盘了。

我们可以看到,某些层次负责的是对下层不同实现的抽象,从而对上层屏蔽实现细节。比方说 VFS 对上层(系统调用层)来说提供了统一的调用接口,同时对下层中不同的文件系统规约了实现模型,当新增一种文件系统实现的时候,只需要按照这种模型来设计,就可以无缝插入到 Linux 文件系统中。

img

那么,为什么这么多系统一定要做分层的设计呢?答案是分层设计存在一定的优势。


二、分层有什么好处

模块化

**分层的设计可以简化系统设计,让不同的人专注做某一层次的事情。**想象一下,如果你要设计一款网络程序却没有分层,该是一件多么痛苦的事情。

因为你必须是一个通晓网络的全才,要知道各种网络设备的接口是什么样的,以便可以将数据包发送给它。你还要关注数据传输的细节,并且需要处理类似网络拥塞,数据超时重传这样的复杂问题。当然了,你更需要关注数据如何在网络上安全传输,不会被别人窥探和篡改。

而有了分层的设计,你只需要专注设计应用层的程序就可以了,其他的,都可以交给下面几层来完成。

复用性

**再有,分层之后可以做到很高的复用。**比如,我们在设计系统 A 的时候,发现某一层具有一定的通用性,那么我们可以把它抽取独立出来,在设计系统 B 的时候使用起来,这样可以减少研发周期,提升研发的效率。

拓展性

**最后一点,分层架构可以让我们更容易做横向扩展。**如果系统没有分层,当流量增加时我们需要针对整体系统来做扩展。但是,如果我们按照上面提到的三层架构将系统分层后,那么我们就可以针对具体的问题来做细致的扩展。

比如说,业务逻辑里面包含有比较复杂的计算,导致 CPU 成为性能的瓶颈,那这样就可以把逻辑层单独抽取出来独立部署,然后只对逻辑层来做扩展,这相比于针对整体系统扩展所付出的代价就要小的多了。

横向扩展是高并发系统设计的常用方法之一,既然分层的架构可以为横向扩展提供便捷, 那么支撑高并发的系统一定是分层的系统。


三、如何来做系统分层

说了这么多分层的优点,那么当我们要做分层设计的时候,需要考虑哪些关键因素呢?

确定层次

在我看来,最主要的一点就是你需要理清楚每个层次的边界是什么。你也许会问:“如果按照三层架构来分层的话,每一层的边界不是很容易就界定吗?”

没错,当业务逻辑简单时,层次之间的边界的确清晰,开发新的功能时也知道哪些代码要往哪儿写。但是当业务逻辑变得越来越复杂时,边界就会变得越来越模糊

定义接口

任何一个系统中都有用户系统,最基本的接口是返回用户信息的接口,它调用逻辑层的 GetUser 方法,GetUser 方法又和 User DB 交互获取数据,就像下图左边展示的样子。

这时,产品提出一个需求,在 APP 中展示用户信息的时候,如果用户不存在,那么要自动给用户创建一个用户。同时,要做一个 HTML5 的页面,HTML5 页面要保留之前的逻辑,也就是不需要创建用户。这时逻辑层的边界就变得不清晰,表现层也承担了一部分的业务逻辑(将获取用户和创建用户接口编排起来)。

img

遵循设计原则

使用设计原则如单一职责原则、依赖倒置原则等,确保每个层次都专注于一个特定的功能。这有助于确保系统的一致性和可维护性。

那我们要如何做呢?参照阿里发布的《阿里巴巴 Java 开发手册 v1.4.0(详尽版)》,我们可以将原先的三层架构细化成下面的样子:

	img

我来解释一下这个分层架构中的每一层的作用。

  • 终端显示层:各端模板渲染并执行显示的层。当前主要是 Velocity 渲染,JS 渲染, JSP 渲染,移动端展示等。
  • 开放接口层:将 Service 层方法封装成开放接口,同时进行网关安全控制和流量控制等。
  • Web 层:主要是对访问控制进行转发,各类基本参数校验,或者不复用的业务简单处理等。
  • Service 层:业务逻辑层。
  • Manager 层:通用业务处理层。这一层主要有两个作用,其一,你可以将原先 Service 层的一些通用能力下沉到这一层,比如与缓存和存储交互策略,中间件的接入;其二,你也可以在这一层封装对第三方接口的调用,比如调用支付服务,调用审核服务等。
  • DAO 层:数据访问层,与底层 MySQL、Oracle、Hbase 等进行数据交互。
  • 外部接口或第三方平台:包括其它部门 RPC 开放接口,基础平台,其它公司的 HTTP 接口。

在这个分层架构中主要增加了 Manager 层,它与 Service 层的关系是:Manager 层提供原子的服务接口,Service 层负责依据业务逻辑来编排原子接口。

以上面的例子来说,Manager 层提供创建用户和获取用户信息的接口,而 Service 层负责将这两个接口组装起来。这样就把原先散布在表现层的业务逻辑都统一到了 Service 层,每一层的边界就非常清晰了。

除此之外,分层架构需要考虑的另一个因素,是层次之间一定是相邻层互相依赖,数据的流转也只能在相邻的两层之间流转。

我们还是以三层架构为例,数据从表示层进入之后一定要流转到逻辑层,做业务逻辑处理,然后流转到数据访问层来和数据库交互。那么你可能会问:“如果业务逻辑很简单的话可不可以从表示层直接到数据访问层,甚至直接读数据库呢?”

其实从功能上是可以的,但是从长远的架构设计考虑,这样会造成层级调用的混乱,比方说如果表示层或者业务层可以直接操作数据库,那么一旦数据库地址发生变更,你就需要在多个层次做更改,这样就失去了分层的意义,并且对于后面的维护或者重构都会是灾难性的。


四、分层架构的不足

任何事物都不可能是尽善尽美的,分层架构虽有优势也会有缺陷。

复杂性问题

它最主要的一个缺陷就是增加了代码的复杂度。这是显而易见的嘛,明明可以在接收到请求后就可以直接查询数据库获得结果,却偏偏要在中间插入多个层次,并且有可能每个层次只是简单地做数据的传递。有时增加一个小小的需求也需要更改所有层次上的代码,看起来增加了开发的成本,并且从调试上来看也增加了复杂度,原本如果直接访问数据库我只需要调试一个方法,现在我却要调试多个层次的多个方法。

性能问题

另外一个可能的缺陷是,如果我们把每个层次独立部署,层次间通过网络来交互,那么多层的架构在性能上会有损耗。这也是为什么服务化架构性能要比单体架构略差的原因,也就是所谓的**“多一跳”**问题。

灵活性问题

过于刚性的分层结构可能使系统难以适应变化。在一些需求频繁变更的项目中,可能需要更灵活的架构设计。


那我们是否要选择分层的架构呢?答案当然是肯定的。

你要知道,任何的方案架构都是有优势有缺陷的,天地尚且不全何况我们的架构呢?分层架构固然会增加系统复杂度,也可能会有性能的损耗,但是相比于它能带给我们的好处来说,这些都是可以接受的,或者可以通过其它的方案解决的。我们在做决策的时候切不可以偏概全,因噎废食。


五、回顾&小结

在系统设计中,分层架构是一种强大而常见的设计模式。它通过将系统划分为不同的层次,每个层次专注于特定功能,提高了系统的可维护性、可扩展性和模块化。

分层架构有着多种形式,如MVC、OSI网络模型、TCP/IP协议等,适用于不同领域和问题。这种设计模式的优势包括模块化、复用性和横向扩展的便利性。

然而,分层架构也存在一些缺陷,包括增加代码复杂性、性能损耗以及过于刚性可能导致难以适应变化。在选择架构时,需要权衡各方面的利弊,根据项目需求和特点做出明智的决策。

分层架构是项目中用到的最多的架构模式之一,核心思想是归类和解耦,实现有多种方式,不应局限于三层,四层,也可能是两层,五层,六层,具体以实际的项目为准。

实际每一层还会有一些变化,不同的设计模式和架构模式实现的分层和代码的组织方式也是不同的,没有完全一样的架构,合适的就是最好的。

总体而言,分层架构为软件系统提供了一种有力的组织和设计方式,为系统的健壮性和可维护性奠定了基础。

相关文章:

「 系统设计 」 为什么要做架构分层?

「 系统设计 」 为什么要做架构分层? 参考&鸣谢 3.设计模式之分层思维:为什么要做代码分层架构? 从零开始学架构(八)分层架构和设计模式 架构模式之分层架构总结 文章目录 「 系统设计 」 为什么要做架构分层&…...

4:kotlin 方法(Functions)

想要声明一个函数需要使用fun关键字 fun hello() {return println("Hello, world!") }fun main() {hello()// Hello, world! }格式: fun 方法名(参数1: 参数1类型, 参数2 : 参数2类型, ...): 返回值类型 {方法体return 返回值 }fun 方法名(参数1: 参数1类型, 参数2…...

Pycharm run 输出界面控制一行能够输出的元素个数

Pycharm run 输出界面控制一行能够输出的元素个数 今天遇到了一个问题,当我们在 Pycharm 中打印输出数组时,如果数组一行的元素个数过多,那么我们在打印时就会出现以下问题。 代码如下: import numpy as npx np.array([[0., 0.7…...

C++初级项目webserver项目流程介绍(2)

一、引言 C的webserver项目是自己在学完网络编程后根据网课的内容做的一个初级的网络编程项目。 这个项目的效果是可以在浏览器通过输入网络IP地址和端口,然后打开对应的文件目录 效果如下: 也可以打开文件夹后点击目录,打开到对应的文件夹…...

SIPp mac和debian用法可能略有差别

<ereg regexp"<(.*)>" search_in"hdr" header"Contact:" check_it"true" assign_to"dummy,remote_contact"/> debian没事&#xff0c;但mac报错 <变&lt >变&gt 就都冇问题了 https://github.…...

echarts的横向柱状图文字省略,鼠标移入显示内容 vue3

效果图 文字省略 提示 如果是在x轴上的&#xff0c;就在x轴上添加triggerEvent: true,如果是y轴就在y轴添加&#xff0c;我是在y轴上添加的 并且自定义的方法&#xff08;我取名为extension&#xff09; // echarts 横向省略文字 鼠标移入显示内容 export const extension…...

laravel8安装多应用多模块(笔记三)

先安装laravel8 Laravel 安装&#xff08;笔记一&#xff09;-CSDN博客 一、进入项目根目录安装 laravel-modules composer require nwidart/laravel-modules 二、 大于laravel5需配置provider&#xff0c;自动生成配置文件 php artisan vendor:publish --provider"Nwid…...

Vue组件的几种通信方式

这里写目录标题 Vue组件的几种通信&#xff08;数据传递&#xff09;方式非父子组件间通信&#xff08;Bus事件总线&#xff09;介绍实例 非父子通信-provide&inject1.作用2.场景3.语法4.注意 父子组件间的通信固定props属性名&#xff08;v-model&#xff09;介绍实例 不固…...

golang panic关键词执行原理与代码分析

使用的go版本为 go1.21.2 首先我们写一个简单的panic调度与捕获代码 package mainfunc main() {defer func() {recover()}()panic("panic test") }通过go build -gcflags -S main.go获取到对应的汇编代码 可以看到当我们调度panic时&#xff0c;Go的编译器会将这段…...

Error running Tomcat8: Address localhost:1099 is already in use 错误解决

摘要: 有时候运行web项目的时候会遇到 Error running Tomcat8: Address localhost:1099 is already in use 的错误&#xff0c;导致web项目无法运行。这篇 blog 介绍了解决办法。 有时候运行web项目的时候会遇到 Error running Tomcat8: Address localhost:1099 is already in …...

android studio如何给安卓虚拟机发送短信

首先&#xff0c;cd到指定路径 默认情况下&#xff0c;Android SDK通常安装在以下位置&#xff1a; Windows&#xff1a;C:\Users\YourUsername\AppData\Local\Android\Sdk\platform-toolsmacOS&#xff1a;/Users/YourUsername/Library/Android/sdk/platform-toolsLinux&…...

立体仓库PLC控制系统子站诊断功能块

// //获取profinet网络已组态站信息 // //MODE:0自动辨识是获取组态信息还是错误信息 //MODE:1获取IO 设备从站已组态 //MODE:2获取IO 设备 从站故障 //MODE:3获取IO 设备 从站已禁用 //MODE:4获取IO 设备 从站存在 //MODE:5获取IO 设备 从站出现问题 // //站点状态字节位含义 …...

NFT Insider115:The Sandbox开设元宇宙Diorama快闪店,​YGG Web3 游戏峰会已开幕

引言&#xff1a;NFT Insider由NFT收藏组织WHALE Members、BeepCrypto联合出品&#xff0c;浓缩每周NFT新闻&#xff0c;为大家带来关于NFT最全面、最新鲜、最有价值的讯息。每期周报将从NFT市场数据&#xff0c;艺术新闻类&#xff0c;游戏新闻类&#xff0c;虚拟世界类&#…...

【Redis篇】简述Java中操作Redis的方法

文章目录 &#x1f384;简述Jedis&#x1f384;Jedis优点&#x1f354;使用Jedis连接Redis⭐进行测试&#x1f388;进行测试 Redis&#xff08;Remote Dictionary Server&#xff09;是一种流行的高性能内存数据库&#xff0c;广泛应用于各种应用程序和系统中。作为Java开发人员…...

深度解读英伟达新一轮对华特供芯片H20、L20、L2的定位

大家好&#xff0c;我是极智视界&#xff0c;欢迎关注我的公众号&#xff0c;获取我的更多前沿科技分享 邀您加入我的知识星球「极智视界」&#xff0c;星球内有超多好玩的项目实战源码和资源下载&#xff0c;链接&#xff1a;https://t.zsxq.com/0aiNxERDq 因为一直从事 AI 工…...

一起学docker系列之九docker运行mysql 碰到的各种坑及解决方法

目录 前言1 Docker 运行mysql命令2 坑一&#xff1a;无法读取/etc/mysql/conf.d目录的问题3 坑二&#xff1a;/tmp/ibnr0mis 文件无法创建/写入的问题4 坑三&#xff1a;Navicat 连接错误&#xff08;1045-access denied&#xff09;5 坑四&#xff1a;MySQL 登录失败问题结语 …...

利用Nginx与php处理方式不同绕过Nginx_host实现SQL注入

目录 首先需要搭建环境 nginxphpmysql环境&#xff1a; 搭建网站 FILTER_VALIDATE_EMAIL 绕过 方法1&#xff1a;冒号号分割host字段 方法2&#xff1a;冒号号分割host字段 方法3&#xff1a;SNI扩展绕过 首先需要搭建环境 nginxphpmysql环境&#xff1a; php安装包&a…...

分割list 批量插入数据指定条数数据

一、代码层面切割好list&#xff0c;然后插入 // package org.apache.commons.collections4; 先将list切成1000条一份 List<List<DeptDO>> p1 ListUtils.partition(deptList, 1000); for (List<DeptDO> deptDOS : p1) { // 1000条一次批量插入systemDeptMa…...

Arduino库之 LedControl 库说明文档

LedControl 库最初是为基于 8 位 AVR 处理器的 Arduino 板编写的。用于通过MAX7219芯片控制LED矩阵和7段数码管。但由于该代码不使用处理器的任何复杂的内部功能&#xff0c;因此具有高度可移植性&#xff0c;并且应该在任何支持 和 功能的 Arduino&#xff08;类似&#xff09…...

Hadoop学习总结(MapReduce的数据去重)

现在假设有两个数据文件 file1.txtfile2.txt2018-3-1 a 2018-3-2 b 2018-3-3 c 2018-3-4 d 2018-3-5 a 2018-3-6 b 2018-3-7 c 2018-3-3 c2018-3-1 b 2018-3-2 a 2018-3-3 b 2018-3-4 d 2018-3-5 a 2018-3-6 c 2018-3-7 d 2018-3-3 c 上述文件 file1.txt 本身包含重复数据&…...

label-studio的使用教程(导入本地路径)

文章目录 1. 准备环境2. 脚本启动2.1 Windows2.2 Linux 3. 安装label-studio机器学习后端3.1 pip安装(推荐)3.2 GitHub仓库安装 4. 后端配置4.1 yolo环境4.2 引入后端模型4.3 修改脚本4.4 启动后端 5. 标注工程5.1 创建工程5.2 配置图片路径5.3 配置工程类型标签5.4 配置模型5.…...

SpringBoot+uniapp 的 Champion 俱乐部微信小程序设计与实现,论文初版实现

摘要 本论文旨在设计并实现基于 SpringBoot 和 uniapp 的 Champion 俱乐部微信小程序&#xff0c;以满足俱乐部线上活动推广、会员管理、社交互动等需求。通过 SpringBoot 搭建后端服务&#xff0c;提供稳定高效的数据处理与业务逻辑支持&#xff1b;利用 uniapp 实现跨平台前…...

【学习笔记】深入理解Java虚拟机学习笔记——第4章 虚拟机性能监控,故障处理工具

第2章 虚拟机性能监控&#xff0c;故障处理工具 4.1 概述 略 4.2 基础故障处理工具 4.2.1 jps:虚拟机进程状况工具 命令&#xff1a;jps [options] [hostid] 功能&#xff1a;本地虚拟机进程显示进程ID&#xff08;与ps相同&#xff09;&#xff0c;可同时显示主类&#x…...

MySQL账号权限管理指南:安全创建账户与精细授权技巧

在MySQL数据库管理中&#xff0c;合理创建用户账号并分配精确权限是保障数据安全的核心环节。直接使用root账号进行所有操作不仅危险且难以审计操作行为。今天我们来全面解析MySQL账号创建与权限分配的专业方法。 一、为何需要创建独立账号&#xff1f; 最小权限原则&#xf…...

基于Java+VUE+MariaDB实现(Web)仿小米商城

仿小米商城 环境安装 nodejs maven JDK11 运行 mvn clean install -DskipTestscd adminmvn spring-boot:runcd ../webmvn spring-boot:runcd ../xiaomi-store-admin-vuenpm installnpm run servecd ../xiaomi-store-vuenpm installnpm run serve 注意&#xff1a;运行前…...

篇章二 论坛系统——系统设计

目录 2.系统设计 2.1 技术选型 2.2 设计数据库结构 2.2.1 数据库实体 1. 数据库设计 1.1 数据库名: forum db 1.2 表的设计 1.3 编写SQL 2.系统设计 2.1 技术选型 2.2 设计数据库结构 2.2.1 数据库实体 通过需求分析获得概念类并结合业务实现过程中的技术需要&#x…...

6.9-QT模拟计算器

源码: 头文件: widget.h #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QMouseEvent>QT_BEGIN_NAMESPACE namespace Ui { class Widget; } QT_END_NAMESPACEclass Widget : public QWidget {Q_OBJECTpublic:Widget(QWidget *parent nullptr);…...

跨平台商品数据接口的标准化与规范化发展路径:淘宝京东拼多多的最新实践

在电商行业蓬勃发展的当下&#xff0c;多平台运营已成为众多商家的必然选择。然而&#xff0c;不同电商平台在商品数据接口方面存在差异&#xff0c;导致商家在跨平台运营时面临诸多挑战&#xff0c;如数据对接困难、运营效率低下、用户体验不一致等。跨平台商品数据接口的标准…...

初探用uniapp写微信小程序遇到的问题及解决(vue3+ts)

零、关于开发思路 (一)拿到工作任务,先理清楚需求 1.逻辑部分 不放过原型里说的每一句话,有疑惑的部分该问产品/测试/之前的开发就问 2.页面部分(含国际化) 整体看过需要开发页面的原型后,分类一下哪些组件/样式可以复用,直接提取出来使用 (时间充分的前提下,不…...

【QT控件】显示类控件

目录 一、Label 二、LCD Number 三、ProgressBar 四、Calendar Widget QT专栏&#xff1a;QT_uyeonashi的博客-CSDN博客 一、Label QLabel 可以用来显示文本和图片. 核心属性如下 代码示例: 显示不同格式的文本 1) 在界面上创建三个 QLabel 尺寸放大一些. objectName 分别…...