解耦:哪些方法可以用来解耦代码

2024-05-25 07:44
文章标签 代码 方法 用来

本文主要是介绍解耦:哪些方法可以用来解耦代码,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

1.引用

2.为何解耦如此重要

3.如何判断代码是否需要解耦

4.如何给代码解耦

5.思考题


1.引用

        前面我们曾经讲到,重构可以分为大型重构和小型重构。小型重构的主要目的是提高代码的可读性,大型重构的主要目的是解耦。本节讲解如何对代码进行解耦。

2.为何解耦如此重要

        在软件的设计与开发过程中,我们需要关注代码的复杂度问题。复杂的代码经常有可读性、可维护性方面的问题,那么,如何控制代码的复杂度呢?其实,控制代码的复杂度的手段有很多,效果显著的应该是解耦,因为解耦可以使代码高内聚、低耦合。利用解耦的方式对代码进行重构可以有效控制代码的复杂度。

        实际上,”高内聚、低耦合”是一种通用的设计思想,它不仅可以指导细粒度的类之向关系的设计,还能指导粗粒度的系统、架构、模块的设计。相比代码规范,它能够在更高层次上提高代码的可读性和可维护性。

        无论是阅读代码还是修改代码,“高内聚、低耦合”特性可以让我们聚焦在某一模块或类上,不需要过多了解其他模块或类的代码,从而降低阅读代码和修改代码的难度。因为依赖关系简单,耦合度低,所以修改代码时不会牵一发而动全身,代码改动集中,引入bug的风险降低。

        代码“高内聚、低耦合”意味着代码的结构清晰,分层和模块化合理,依赖关系简单,模块或类之间的耦合度低。对于“高内聚、低耦合”的代码,即使某个类或模块内部的设计不合理,代码质量不算高,影响范围也是有限的。我们可以聚焦这个模块或类并进行小型重构相比代码结构的调整,这种改动集中的小型重构的难度大幅降低。

3.如何判断代码是否需要解耦

        如果修改一段功能代码时出现“牵一发而动全身”的情况,那么说明这个项目的代码耦合度过高,需要对其进行解耦。除此之外,我们还有一个直观的衡量方式,就是先把项目代码中的模块之间、类之间的依赖关系画出来,再根据依赖关系图的复杂度来判断项目代码是否需要解耦。如果模块之间、类之间的依赖关系复杂、混乱,那么说明代码结构存在问题,此时,我们可以通过解耦让依赖关系变得简单、清晰。

4.如何给代码解耦

        接下来,我们探讨一下如何给代码解耦。

        1.通过封装与抽象来解耦

        封装和抽象可以应用在多种代码设计场景中,如系统、块、类库、组件、接口和类等的设计。封装和抽象可以有效地隐藏实现的复杂性,隔离实现的易变性,给上层模块提供稳定目易用的接口。

        例如,UNIX系统提供的文件操作函数open()使用简单,但其底层实现复杂,涉及权限控制、并发控制和物理存储等。我们通过将open()封装为一个抽象的函数,能够有效控制代码复杂性的蔓延,将代码复杂性封装在局部代码中。除此之外,因为open()函数基于抽象而非具体实现来定义,所以我们在改动open()函数的底层实现时,并不需要改动依赖它的上层代码。

        2.通过引入中间层来解耦

        中间层能够简化模块之间或类之间的依赖关系。图5-1是引入中间层前后的依赖关系对比图。在引入数据存储中间层之前,A、B和C模块都要依赖内存一级缓存、Redis 二级缓存和DB 持久化存储3个模块。在引入数据存储中间层之后,A、B和C模块只需要依赖数据存中间层模块。从图5-1可以看出,中间层的引入简化了模块之间的依赖关系,让代码结构更加清晰。

        在进行重构时,中间层可以起到过渡作用,实现开发和重构同步进行,且不互相干扰。例如,某个接口的设计有问题,我们需要修改它的定义,于是,所有调用这个接口的代码都要做相应改动。如果新开发的代码也使用这个接口,那么开发与重构之间会产生冲突。为了使重构“小步快跑”,我们可以通过以下4个阶段完成对接口的修改。

        1)第一阶段:引入一个中间层,利用中间层“包裹”旧接口,提供新接口。

        2)第二阶段:新开发的代码依赖中间层提供的新接口。

        3)第三阶段:将依赖旧接口的代码改为调用新接口。

        4)第四阶段:确保所有代码中都调用新接口之后,删除旧接口。通过引入中间层,我们可以分阶段完成重构。由于每个阶段的开发工作量都不会很大,可以在短时间内完成,因此重构与开发发生冲突的概率变小了。

        3.通过模块化、分层来解耦

        模块化是构建复杂系统的常用手段。模块化还广泛用于建筑、机械制造等行业。对于UNIX这样复杂的系统,我们很难掌控其所有实现细节。之所以人们能够开发出UNIX这样复杂的系统,并且能够对其进行维护,主要原因是将该系统划分成了多个独立模块,如进程调度、进程通信、内存管理、虚拟文件系统和网络接口等模块。模块之间通过接口通信,模块之间的耦合度很小,每个小型团队负责一个独立的高内聚模块的开发,最终,将各个模块组合构成一个复杂的系统。

        实际上,模块化思想在SOA(Service-Oriented Architecture,面向服务的架构)、微服务类库,以及类和函数的设计等方面都有所体现。模块化的本质是“分而治之”。

        我们将目光聚焦到代码层面。在开发代码时,我们要有模块化意识,将每个模块都当作个独立的类库来开发,只提供封装了内部实现细节的接口给其他模块使用,这样可以降低模块之间的耦合度。

        除模块化以外,分层也是构建复杂系统的常用手段。例如,UNIX系统就是基于分层思想之间的耦合度。开发的,它大致分为3层:内核层、系统调用层和应用层。每一层都封装了实现细节,并且暴露抽象的接口供上层使用。而且,任意一层部可以被重新实现,不会影响其他层的代码。面对复杂系统的开发,我们要善于应用分展技术,尽量将容易复用、与具体业务关系不大的代码下沉到下层,将容易变动、与具体业务强相关的代码移到上层。

        4.利用经典的代码设计思想和设计原则来解耦

        我们总结一下可以用来解耦的代码设计原则和设计思想。

        (1)单一职责原则

        内聚性和耦合性二者并非相互独立。高内聚使得代码低耦合,而实现高内聚的重要指导则是单一职责原则。如果模块或类的职责单一,那么依赖它们的类和它们依赖的类较少,代码的耦合度也就降低了。

        (2)基于接口而非实现编程

        如果我们利用“基于接口而非实现编程”思想来编程,那么,在有依赖关系的两个模块或类之间,一个模块或类的改动不会影响另一个模块或类。这就相当于将一种强依赖关系(强合)解耦为了弱依赖关系(弱耦合)。

        (3) 依赖注入

        与“基于接口而非实现编程”类似,依赖注入也能将模块或类之间的强耦合变为弱耦合尽管依赖注入无法将本应该有依赖关系的两个类解耦为没有依赖关系,但可以使二者的耦合关系不再像原来那么紧密,方便将某个类锁依赖的类替换为其他类。

        (4)多用组合,少用继承

        继承是一种强依赖关系,父类与子类高度耦合,且这种耦合关系非常脆弱,父类的每一次改动都会影响其所有子类。组合是一种弱依赖关系。对于复杂的继承关系,我们可以利用组合替换继承,以达到解耦的目的。

        (5) LoD

        LoD 的定义描述是:不应该存在直接依赖关系的类之间不要有依赖,有依赖关系的类之间量只依赖必要的接口。从LoD的定义描述中可以看出,使用LoD的目的就是实现代码的低耦合。除上述设计思想和设计原则以外,大部分设计模式也能起到解耦的效果,关于这一部分内容,在我们之前都有讲过。

5.思考题

        实际上,在平时的开发中,解耦到处可见,例如,Spring中的AOP能实现业务代码与非业务代码的解耦,IoC 能实现对象的创建和使用的解耦,除此之外,读者还能想到哪些解耦场景?

这篇关于解耦:哪些方法可以用来解耦代码的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1000895

相关文章

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象

活用c4d官方开发文档查询代码

当你问AI助手比如豆包,如何用python禁止掉xpresso标签时候,它会提示到 这时候要用到两个东西。https://developers.maxon.net/论坛搜索和开发文档 比如这里我就在官方找到正确的id描述 然后我就把参数标签换过来

浅谈主机加固,六种有效的主机加固方法

在数字化时代,数据的价值不言而喻,但随之而来的安全威胁也日益严峻。从勒索病毒到内部泄露,企业的数据安全面临着前所未有的挑战。为了应对这些挑战,一种全新的主机加固解决方案应运而生。 MCK主机加固解决方案,采用先进的安全容器中间件技术,构建起一套内核级的纵深立体防护体系。这一体系突破了传统安全防护的局限,即使在管理员权限被恶意利用的情况下,也能确保服务器的安全稳定运行。 普适主机加固措施:

webm怎么转换成mp4?这几种方法超多人在用!

webm怎么转换成mp4?WebM作为一种新兴的视频编码格式,近年来逐渐进入大众视野,其背后承载着诸多优势,但同时也伴随着不容忽视的局限性,首要挑战在于其兼容性边界,尽管WebM已广泛适应于众多网站与软件平台,但在特定应用环境或老旧设备上,其兼容难题依旧凸显,为用户体验带来不便,再者,WebM格式的非普适性也体现在编辑流程上,由于它并非行业内的通用标准,编辑过程中可能会遭遇格式不兼容的障碍,导致操

poj 1258 Agri-Net(最小生成树模板代码)

感觉用这题来当模板更适合。 题意就是给你邻接矩阵求最小生成树啦。~ prim代码:效率很高。172k...0ms。 #include<stdio.h>#include<algorithm>using namespace std;const int MaxN = 101;const int INF = 0x3f3f3f3f;int g[MaxN][MaxN];int n

透彻!驯服大型语言模型(LLMs)的五种方法,及具体方法选择思路

引言 随着时间的发展,大型语言模型不再停留在演示阶段而是逐步面向生产系统的应用,随着人们期望的不断增加,目标也发生了巨大的变化。在短短的几个月的时间里,人们对大模型的认识已经从对其zero-shot能力感到惊讶,转变为考虑改进模型质量、提高模型可用性。 「大语言模型(LLMs)其实就是利用高容量的模型架构(例如Transformer)对海量的、多种多样的数据分布进行建模得到,它包含了大量的先验

【北交大信息所AI-Max2】使用方法

BJTU信息所集群AI_MAX2使用方法 使用的前提是预约到相应的算力卡,拥有登录权限的账号密码,一般为导师组共用一个。 有浏览器、ssh工具就可以。 1.新建集群Terminal 浏览器登陆10.126.62.75 (如果是1集群把75改成66) 交互式开发 执行器选Terminal 密码随便设一个(需记住) 工作空间:私有数据、全部文件 加速器选GeForce_RTX_2080_Ti

计算机毕业设计 大学志愿填报系统 Java+SpringBoot+Vue 前后端分离 文档报告 代码讲解 安装调试

🍊作者:计算机编程-吉哥 🍊简介:专业从事JavaWeb程序开发,微信小程序开发,定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事,生活就是快乐的。 🍊心愿:点赞 👍 收藏 ⭐评论 📝 🍅 文末获取源码联系 👇🏻 精彩专栏推荐订阅 👇🏻 不然下次找不到哟~Java毕业设计项目~热门选题推荐《1000套》 目录 1.技术选型 2.开发工具 3.功能

代码随想录冲冲冲 Day39 动态规划Part7

198. 打家劫舍 dp数组的意义是在第i位的时候偷的最大钱数是多少 如果nums的size为0 总价值当然就是0 如果nums的size为1 总价值是nums[0] 遍历顺序就是从小到大遍历 之后是递推公式 对于dp[i]的最大价值来说有两种可能 1.偷第i个 那么最大价值就是dp[i-2]+nums[i] 2.不偷第i个 那么价值就是dp[i-1] 之后取这两个的最大值就是d

pip-tools:打造可重复、可控的 Python 开发环境,解决依赖关系,让代码更稳定

在 Python 开发中,管理依赖关系是一项繁琐且容易出错的任务。手动更新依赖版本、处理冲突、确保一致性等等,都可能让开发者感到头疼。而 pip-tools 为开发者提供了一套稳定可靠的解决方案。 什么是 pip-tools? pip-tools 是一组命令行工具,旨在简化 Python 依赖关系的管理,确保项目环境的稳定性和可重复性。它主要包含两个核心工具:pip-compile 和 pip