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

目录

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.rhkb.cn/news/330231.html

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

相关文章

es问题汇总--待完善

1. 查询某个索引库中数据总量 方式一: CountRequest 鄙人喜欢这种方式 public long getTotalNum(String indexName) throws IOException {CountRequest countRequest new CountRequest(indexName);// 如果需要,你可以在这里添加查询条件// countReques…

MySQL之架构设计与历史(一)

架构设计与历史 概述 和其他数据库系统相比,MySQL有点与众不同,它的架构可以在多种不同场景中应用并发挥好的作用,但同时也会带来一点选择上的困难。MySQL并不完美,却足够灵活,能够适应高要求的环境,例如…

【全开源】班级管家微信小程序(FastAdmin+ThinkPHP)

班级管家微信小程序 班级管家微信小程序,作为一款专注于家校沟通、作业管理、成绩发布等方面的工具,凭借其丰富的特色功能和显著的优势,已经成为广大教师、家长和学生日常学习生活中不可或缺的一部分。 一、特色功能 家校沟通便捷&#xff…

高效利用键盘上的 caps lock(大写键)实现中英切换

先看效果 在中文输入环境中,Caps Lock 键经常被忽视,占据了键盘上的黄金位置却很少派上用场。接下来,我将介绍如何将这个闲置的键合理利用,让它变得更加实用。 第一步 设置: 我以五笔为例: 1.输入法默认…

CCF20230301——田地丈量

CCF20230301——田地丈量 代码如下&#xff1a; #include<bits/stdc.h> using namespace std; int main() {int n,a,b;cin>>n>>a>>b;int x1,x2,y1,y2,x,y,sum0;for(int i0;i<n;i){cin>>x1>>y1>>x2>>y2;xmin(x2,a)-max(x1,…

基础3 探索JAVA图形编程桌面:逻辑图形组件实现

在一个宽敞明亮的培训教室里&#xff0c;阳光透过窗户柔和地洒在地上&#xff0c;教室里摆放着整齐的桌椅。卧龙站在讲台上&#xff0c;面带微笑&#xff0c;手里拿着激光笔&#xff0c;他的眼神中充满了热情和期待。他的声音清晰而洪亮&#xff0c;传遍了整个教室&#xff1a;…

k8s 1.28.10 浏览器访问6443查看api,需要证书

添加证书 使用client-certificate-data和client-key-data生成一个p12文件 1.生成client-certificate-data grep client-certificate-data ~/.kube/config | head -n 1 | awk {print $2} | base64 -d >> kubecfg.crt2.生成client-key-data grep client-key-data ~/.kub…

【每日刷题】Day48

【每日刷题】Day48 &#x1f955;个人主页&#xff1a;开敲&#x1f349; &#x1f525;所属专栏&#xff1a;每日刷题&#x1f34d; &#x1f33c;文章目录&#x1f33c; 1. 872. 叶子相似的树 - 力扣&#xff08;LeetCode&#xff09; 2. 114. 二叉树展开为链表 - 力扣&…

字符函数:分类函数与转换函数

字符函数 一.字符分类函数二.字符转换函数 在编程的过程中&#xff0c;我们经常要处理字符和字符串&#xff0c;为了方便操作字符和字符串&#xff0c;C语⾔标准库中提供了一系列库函数&#xff0c;接下来我们就学习⼀下这些函数。 一.字符分类函数 C语言中有⼀系列的函数是专门…

前端请求超时截断,axios timeout设置未生效情况记录

问题描述 前端请求超时截断&#xff0c;axios timeout设置未生效情况记录 timeout设置方式&#xff1a; 表现&#xff08;前端超过5min报错500&#xff0c;直接访问接口超过5min能够正常响应&#xff09;&#xff1a; 问题原因 上面的配置设置时间为1000min&#xff0c;明显…

如何一键生成多个文本二维码?excel表格批量生码的方法

现在很多人会将文本信息做成二维码来展示&#xff0c;当有同类型内容生成大量二维码时&#xff0c;可以使用将文本导入excel表格的方式&#xff0c;将表格中的每条数据批量生成二维码&#xff0c;可以有效提升二维码制作的速度和效率。下面就让小编来将具体的操作步骤分享给大家…

人类交互2 听觉处理和语言中枢

人类听觉概述 人类听觉是指通过耳朵接收声音并将其转化为神经信号&#xff0c;从而使我们能够感知和理解声音信息的能力。听觉是人类五种感觉之一&#xff0c;对我们的日常生活和交流至关重要。 听觉是人类交流和沟通的重要工具。通过听觉&#xff0c;我们能够听到他人的语言…

什么是物联网通信网关?-天拓四方

在信息化、智能化的时代&#xff0c;物联网技术的广泛应用正在逐渐改变我们的生活方式。物联网通过各种传感器和设备&#xff0c;将现实世界与数字世界紧密相连&#xff0c;从而实现智能化、自动化的生活和工作方式。作为物联网生态系统中的重要组成部分&#xff0c;物联网通信…

local dimming(局部调光)介绍

文章目录 1. 什么是local dimming2. 工作原理3. 类型4. 优点5. 缺点和局限7. 技术发展趋势 1. 什么是local dimming local dimming&#xff08;局部调光&#xff09;是电视和显示器中用于提升画面对比度和画质的背光技术。其基本原理是将背光源&#xff08;通常是LED&#xff…

【题解】AB33 相差不超过k的最多数(排序 + 滑动窗口)

https://www.nowcoder.com/practice/562630ca90ac40ce89443c91060574c6?tpId308&tqId40490&ru/exam/oj 排序 滑动窗口 #include <iostream> #include <vector> #include <algorithm> using namespace std;int main() {int n, k;cin >> n &…

MariaDB 给指定列值自动加密(持久数据加触发器)

文章目录 代码插入时&#xff0c;自动加密更新时&#xff0c;自动加密查看触发器数据操作示例update数据取出解密取 注意一次尝试&#xff0c;看加密后数据长度 参考链接&#xff1a; 一篇非常好的讲解触发器的文章&#xff1a;示例、原理MySQL/MariaDB触发器。 用触发器自动加…

许冉直播不治本,京东需要刘强东

图片&#xff5c;影视剧《纸牌屋》剧照 ©自象限原创 作者丨艾AA 编辑丨薛黎 这届618&#xff0c;消费者的热情还未显现&#xff0c;商家的怒火先爆发了。 5月21日京东618开幕次日&#xff0c;多家图书社抵制618图书大促登上了热搜。此次争议与去年双十一京东采销与电…

Predictable MDP Abstraction for Unsupervised Model-Based RL

ICML 2023 paper code Intro 文章提出了一种用于无监督基于模型强化学的方法&#xff0c;称为可预测MDP抽象&#xff08;Predictable MDP Abstraction, PMA&#xff09;。在MBRL中&#xff0c;一个关键部分是能够准确建模环境动力学动态模型。然而&#xff0c;这个预测模型误…

【C语言】程序员自我修养之文件操作

【C语言】程序员自我修养之文件操作 &#x1f525;个人主页&#xff1a;大白的编程日记 &#x1f525;专栏&#xff1a;C语言学习之路 文章目录 【C语言】程序员自我修养之文件操作前言一.文件介绍1.1为什么使用文件1.2文件分类1.3二进制文件和文本文件 二.文件的打开和关闭2.…

数据可视化技术头歌测试合集

努力是为了不平庸~ 学习的最大理由是想摆脱平庸&#xff0c;早一天就多一份人生的精彩&#xff1b;迟一天就多一天平庸的困扰 目录 时间趋势可视化-柱形图 第1关&#xff1a;“大胃王”比赛数据柱形图绘制——绘制柱形图的基本步骤 任务描述 相关知识 观察和处理数据 绘…