设计心得——分层和划分模块
一、分层
在实际的设计开发过程中,对于稍微大一些的项目,基本都涉及到分层。什么是分层呢?其实非常简单,就是利用某种逻辑或域的范围等把整个项目划分成多个层次。它们之间通过接口(可能是简单的函数接口也可以是服务等)进行通信。分层地目的其实非常明显,就是为了整个设计的解耦和重用,使得整个项目结构更清晰和控制更合理,也便 于后期的维护和扩展。
一般来说,分层是在更高层次上进行抽象,它属于对整个项目的横向切分。分层的优点非常多,比如高内聚、低耦合以及便于维护和接口扩展,提供了更好的技术更新接口等等。但在明白其的优势之后,更要明白它的劣势所在:
1、降低性能
增加层次的最主要的问题就是导致一定的性能损失。毕竟大家都明白,直接调用比通过接口处理一下,理论上一定是要快的。特别是在通信量巨大并且并发较高的情况下,其性能的损失会非常的明显。
2、增加复杂性
分层设计需要进行良好的层间接口设计,否则极有可能导致因为接口的问题导致层间的通信问题,比如对于一个任务是需要调用一个接口完成(单一原则)还是一个以上接口(效率)实现呢?这就需要设计者不断的根据实际情况进行调整。
3、工程化的风险
设计者们往往有一个爱好,一旦觉得某项技术不错,便会不断的在这个基础上进行强化,也就是过度设计。体现在分层上就是更乐意通过分层来解决很多问题。虽然分层在很多情况下可以将问题简化,但过多的引入分层等于变相的增加了另外一种复杂性。也就是说,设计者一定要明白,分层的适度性和科学性。而且过多的分层往往导致测试的复杂性和增加测试的难度。
虽然明白了分层的优势,但说起分层来大家可能有点熟悉又陌生的感觉,其实举一个常见的MVC的例子大家就明白了,它其实就是把整个程序分成了三层,上层的表示层用来处理接收的输入数据和处理后返回的数据;中间的控制层用来进行上下的交互数据管理;而最下面的模型层则进行数据的最终存储逻辑控制。
通过MVC明白了这种分层的设计的具像化,那么其它也就好理解了,比如常见的另外一种分层,网络分层,TCP/IP的分层等等。某些情况下,分层类似于见到的过滤器,一层层的过滤掉不同的物质(或者说一层只处理一个或几个业务)。这样,大家应该就对分层有了一个很显性的认识。
但需要注意的是,软件设计的分层往往从不同的角度看有不同的理解,大家不要教条和僵化,慢慢思考、理解和学习即可。
二、模块化
说了分层,再说设计高频遇到的名词,模块。其实模块这个概念就是一组功能相近的软件代码或组件。这里面水儿深着哪。首先,什么是一组,另外什么是功能相近?什么是代码或组件?这个其实没有强制的定义。给大家举个例子,一个函数就有可能是一个模块,而一个类也可能是一个模块,一个文档可能也是。一个软件可能也是…凡此种种。而模块化就是以模块为基础的设计方式。
模块会根据场景不一致而呈现中不同的情况。而上面所提到的功能相近等其实也可以站不同的角度和层次上来看。再举一个例子,一个大型的变电站运行软件,可能分成服务端软件,客户端软件,移动端软件和设备端软件等等。那么从这个角度来看,它们每个都算是一个独立的模块。一般来说,模块属于是在纵向上的划分,即更强功能的组合。
需要提醒的是,不要混淆模块的一些概念,比如在不少的程序语言中,都有模块这个概念。它们和设计中提到的模块基本类似,但也有着一些显著的不同。切记。
模块化设计的优点很多,和分层差不多,毕竟二者都是朝着同一个目的而来的。
模块化设计的主要优点包括:高内聚,低耦合,接口清晰,易维护,方便代码重用及团队协作。但它的缺点也不少:
1、模块化设计增加了设计的难度
不是每个设计者都能很好的把握模块的设计,这就可能导致模块设计的不合理性,进而导致各种问题。
2、降低效率
和分层一样,通过接口调用的模块,理论上会降低整体的效率
3、工程上的过度设计
一如分层,模块的过度设计,同样会导致整个软件的难于控制,过多的模块往往使得业务的碎片化;而过少的模块除了引入了一些复杂性,几乎没有体现出模块的优势。
4、模块的维护
设计完成的模块,需要从开始到结束都一套完善的管理流程,包括文档、工具等。如果开发者们没有按照设计要求进行,则可能导致引入不少的风险。最简单的例子就是不同的模块间,使用了不同的技术标准实现或者引入不相同功能的不同版本的库。都可能导致问题的出现,而且极有可能很难发现问题的原因。
但正如成语说得好,不能“因噎废食”。设计就是一种取舍和妥协!
三、二者关系
在分析了上述的分层和模块后,不少的新手可能会有一个疑问,怎么看待二者的设计上的抽象的不同呢?一般情况下,分层的抽象是高于模块的抽象的,但具体情况上则有可能有所不同 。比如在上面提到的变电站软件中,每个模块中,可能又会划分成不同的层次。这样看来,模块包含着分层。也就是说,实际应用中,分层和模块间没有明确的界限,二者可以互相包容。
其实,稍微大一些软件的设计,一般来说是分层优先,然后进行模块划分。经常可以看到系统的整体设计架构图,就是这样的。但凡是都有例外,分层和模块二者之间其实是一个互相补充互相协作上的抽象关系。从整体抽象看,分层是较大粒度的划分而模块则是较小粒度的划分。也即上面提到的分层是基于横向的水平划分而模块是基于纵向的垂直划分。
一般的情况下,分好的层次中,每层都包含若干个模块。模块间以接口通信,整合后通过层间的接口再与其它层进行通信。层次之间的数据依赖单向为主,但模块间的依赖则灵活很多。
四、二者的应用
分层和模块化的应用场景在不少的场景下是重叠的,但整体上来看,还是可以进行区别划分的。
1、分层的应用
a) 大规模的应用,特别是企业级的应用。包括框架、库和系统等
b) 分布式应用,为更好的协调分布式各个节点间的通信,分层是一个非常好的设计思路
c) Web应用,这个更容易理解,常见的MVC设计在Web服务中体现的最明显
d) 复杂应用,对业务或逻辑处理深度较大,恰恰是分层设计的良好应用场景
e) 其它一些特殊场景
2、模块化的应用
模块化设计几乎是所有的程序设计都离不开的。除非程序很小或者说一些例程,正常情况下,一个软件都要进行模块化的设计。
五、总结
设计一个从抽象到具体,从整体到细节,不断具体而微的过程。俗话说得好“教的曲儿唱不得”。设计不像技巧,多问两下多看两下代码就会用了。所以设计中的一些具体的手段和方法,要不断的从不同的角度不同的场景进行分析学习,并不断在实践中进行检验。反思得失,总结教训,形成自己的一套解决问题、处理问题的逻辑和流程。最终升华为自己的设计思想。
这一定是一个长期的,不断的否定之否定的过程!愿与诸君共勉!
相关文章:
设计心得——分层和划分模块
一、分层 在实际的设计开发过程中,对于稍微大一些的项目,基本都涉及到分层。什么是分层呢?其实非常简单,就是利用某种逻辑或域的范围等把整个项目划分成多个层次。它们之间通过接口(可能是简单的函数接口也可以是服务…...
uniapp使用蓝牙,usb,局域网,打印机打印
使用流程(支持安卓和iOS) 引入SDK 引入原生插件包地址如下 https://github.com/oldfive20250214/UniPrinterDemo 连接设备 安卓支持经典蓝牙、ble蓝牙、usb、局域网(参考API) iOS支持ble蓝牙、局域网(参考API&…...
PQL查询和监控各类中间件
1 prometheus的PQL查询 1.1 Metrics数据介绍 prometheus监控中采集过来的数据统一称为Metrics数据,其并不是代表具体的数据格式,而是一种统计度量计算单位当需要为某个系统或者某个服务做监控时,就需要使用到 metrics prometheus支持的met…...
day1 redis登入指令
[rootlocalhost data]# redis-cli -h ip -p 6379 -a q123q123 Warning: Using a password with -a or -u option on the command line interface may not be safe. ip:6379> 以上, Bigder...
2025 年 AI 网络安全预测
🍅 点击文末小卡片 ,免费获取网络安全全套资料,资料在手,涨薪更快 微软和 OpenAI 宣布延长战略合作伙伴关系,加强对推进人工智能技术的承诺,这表明强大的 AI 将在未来占据主导地位。 随着人工智能 &#x…...
[Windows] 多系统键鼠共享工具 轻松跨系统控制多台电脑
参考原文:[Windows] 多系统键鼠共享工具 轻松跨系统控制多台电脑 还在为多台电脑需要多套键盘鼠标而烦恼吗?是不是在操控 Windows、macOS、Linux 不同系统电脑时手忙脚乱?现在,这些问题通通能解决!Deskflow 软件闪亮登…...
单片机的发展
一、引言 单片机自诞生以来,经历了四十多年的风风雨雨,从最初的工业控制逐步扩展到家电、通信、智能家居等各个领域。其发展过程就像是一场精彩的冒险,每一次技术的革新都像是在未知的海域中开辟新的航线。 二、单片机的发展历程 ÿ…...
Spring 构造器注入和setter注入的比较
一、比较说明 在 Spring 框架中,构造器注入(Constructor Injection)和 Setter 注入(Setter Injection)是实现依赖注入(DI)的两种主要方式。它们的核心区别在于依赖注入的时机、代码设计理念以及…...
uploadlabs通关思路
目录 靶场准备 复现 pass-01 代码审计 执行逻辑 文件上传 方法一:直接修改或删除js脚本 方法二:修改文件后缀 pass-02 代码审计 文件上传 1. 思路 2. 实操 pass-03 代码审计 过程: 文件上传 pass-04 代码审计 文件上传 p…...
迷你世界脚本自定义UI接口:Customui
自定义UI接口:Customui 彼得兔 更新时间: 2024-11-07 15:12:42 具体函数名及描述如下:(除前两个,其余的目前只能在UI编辑器内部的脚本使用) 序号 函数名 函数描述 1 openUIView(...) 打开一个UI界面(注意…...
【情境领导者】评估情境——准备度水平
本系列是看了《情境领导者》一书,结合自己工作的实践经验所做的学习笔记。 在文章【情境领导者】评估情境——什么是准备度-CSDN博客我们提到准备度是由能力和意愿两部分组成的。 准备度水平 而我们要怎么去评估准备度呢?准备度水平是指人们在每项工作中…...
2025 ubuntu24.04系统安装docker
1.查看ubuntu版本(Ubuntu 24.04 LTS) rootmaster:~# cat /etc/os-release PRETTY_NAME"Ubuntu 24.04 LTS" NAME"Ubuntu" VERSION_ID"24.04" VERSION"24.04 LTS (Noble Numbat)" VERSION_CODENAMEnoble IDubun…...
Android中AIDL和HIDL的区别
在Android中,AIDL(Android Interface Definition Language) 和 HIDL(HAL Interface Definition Language) 是两种用于定义跨进程通信接口的语言。AIDL 是 Android 系统最早支持的 IPC(进程间通信࿰…...
通过数据库网格架构构建现代分布式数据系统
在当今微服务驱动的世界中,企业在跨分布式系统管理数据方面面临着越来越多的挑战。数据库网格架构已成为应对这些挑战的强大解决方案,它提供了一种与现代应用架构相匹配的分散式数据管理方法。本文将探讨数据库网格架构的工作原理,以及如何使…...
Python基于Django的医用耗材网上申领系统【附源码、文档说明】
博主介绍:✌Java老徐、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 🍅文末获取源码联系🍅 👇🏻 精彩专栏推荐订阅👇&…...
Python爬虫实战:一键采集电商数据,掌握市场动态!
电商数据分析是个香饽饽,可市面上的数据采集工具要不贵得吓人,要不就是各种广告弹窗。干脆自己动手写个爬虫,想抓啥抓啥,还能学点技术。今天咱聊聊怎么用Python写个简单的电商数据爬虫。 打好基础:搞定请求头 别看爬虫…...
STM32之I2C硬件外设
注意:硬件I2C的引脚是固定的 SDA和SCL都是复用到外部引脚。 SDA发送时数据寄存器的数据在数据移位寄存器空闲的状态下进入数据移位寄存器,此时会置状态寄存器的TXE为1,表示发送寄存器为空,然后往数据控制寄存器中一位一位的移送数…...
【C++】中的赋值初始化和直接初始化的区别
在C中,赋值初始化(也称为拷贝初始化)和直接初始化(也称为构造初始化)虽然常常产生相同的结果,但在某些情况下它们有不同的含义和行为。 赋值初始化(Copy Initialization) 使用等号…...
Python ❀ Unix时间戳转日期或日期转时间戳工具分享
设计一款Unix时间戳和日期转换工具,其代码如下: from datetime import datetimeclass Change_Date_Time(object):def __init__(self, date_strNone, date_numNone):self.date_str date_strself.date_num date_num# 转时间戳def datetime2timestamp(s…...
本地部署Dify及避坑指南
Dify作为开源的大模型应用开发平台,支持本地私有化部署,既能保障数据安全,又能实现灵活定制。但对于新手而言,从环境配置到服务启动可能面临诸多挑战。本文结合实战经验,手把手教你从零部署Dify,并总结高频…...
stm32G473的flash模式是单bank还是双bank?
今天突然有人stm32G473的flash模式是单bank还是双bank?由于时间太久,我真忘记了。搜搜发现,还真有人和我一样。见下面的链接:https://shequ.stmicroelectronics.cn/forum.php?modviewthread&tid644563 根据STM32G4系列参考手…...
Lombok 的 @Data 注解失效,未生成 getter/setter 方法引发的HTTP 406 错误
HTTP 状态码 406 (Not Acceptable) 和 500 (Internal Server Error) 是两类完全不同的错误,它们的含义、原因和解决方法都有显著区别。以下是详细对比: 1. HTTP 406 (Not Acceptable) 含义: 客户端请求的内容类型与服务器支持的内容类型不匹…...
基于距离变化能量开销动态调整的WSN低功耗拓扑控制开销算法matlab仿真
目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.算法仿真参数 5.算法理论概述 6.参考文献 7.完整程序 1.程序功能描述 通过动态调整节点通信的能量开销,平衡网络负载,延长WSN生命周期。具体通过建立基于距离的能量消耗模型&am…...
Java多线程实现之Thread类深度解析
Java多线程实现之Thread类深度解析 一、多线程基础概念1.1 什么是线程1.2 多线程的优势1.3 Java多线程模型 二、Thread类的基本结构与构造函数2.1 Thread类的继承关系2.2 构造函数 三、创建和启动线程3.1 继承Thread类创建线程3.2 实现Runnable接口创建线程 四、Thread类的核心…...
Python 包管理器 uv 介绍
Python 包管理器 uv 全面介绍 uv 是由 Astral(热门工具 Ruff 的开发者)推出的下一代高性能 Python 包管理器和构建工具,用 Rust 编写。它旨在解决传统工具(如 pip、virtualenv、pip-tools)的性能瓶颈,同时…...
Python ROS2【机器人中间件框架】 简介
销量过万TEEIS德国护膝夏天用薄款 优惠券冠生园 百花蜂蜜428g 挤压瓶纯蜂蜜巨奇严选 鞋子除臭剂360ml 多芬身体磨砂膏280g健70%-75%酒精消毒棉片湿巾1418cm 80片/袋3袋大包清洁食品用消毒 优惠券AIMORNY52朵红玫瑰永生香皂花同城配送非鲜花七夕情人节生日礼物送女友 热卖妙洁棉…...
视频行为标注工具BehaviLabel(源码+使用介绍+Windows.Exe版本)
前言: 最近在做行为检测相关的模型,用的是时空图卷积网络(STGCN),但原有kinetic-400数据集数据质量较低,需要进行细粒度的标注,同时粗略搜了下已有开源工具基本都集中于图像分割这块,…...
Mysql8 忘记密码重置,以及问题解决
1.使用免密登录 找到配置MySQL文件,我的文件路径是/etc/mysql/my.cnf,有的人的是/etc/mysql/mysql.cnf 在里最后加入 skip-grant-tables重启MySQL服务 service mysql restartShutting down MySQL… SUCCESS! Starting MySQL… SUCCESS! 重启成功 2.登…...
基于IDIG-GAN的小样本电机轴承故障诊断
目录 🔍 核心问题 一、IDIG-GAN模型原理 1. 整体架构 2. 核心创新点 (1) 梯度归一化(Gradient Normalization) (2) 判别器梯度间隙正则化(Discriminator Gradient Gap Regularization) (3) 自注意力机制(Self-Attention) 3. 完整损失函数 二…...
mac 安装homebrew (nvm 及git)
mac 安装nvm 及git 万恶之源 mac 安装这些东西离不开Xcode。及homebrew 一、先说安装git步骤 通用: 方法一:使用 Homebrew 安装 Git(推荐) 步骤如下:打开终端(Terminal.app) 1.安装 Homebrew…...
