返回顶部
首页 > 资讯 > 前端开发 > html >怎么降低代码的圈复杂度
  • 735
分享到

怎么降低代码的圈复杂度

2024-04-02 19:04:59 735人浏览 泡泡鱼
摘要

本篇内容主要讲解“怎么降低代码的圈复杂度”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“怎么降低代码的圈复杂度”吧!0. 什么是圈复杂度可能你之前没有听说过这个词

本篇内容主要讲解“怎么降低代码的圈复杂度”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“怎么降低代码的圈复杂度”吧!

0. 什么是圈复杂度

可能你之前没有听说过这个词,也会好奇这是个什么东西是用来干嘛的,在维基百科上有这样的解释。

Cyclomatic complexity is a software metric used to indicate the complexity of  a program. It is a quantitative measure of the number of linearly independent  paths through a program's source code. It was developed by Thomas J. McCabe, Sr.  in 1976.

简单翻译一下就是,圈复杂度是用来衡量代码复杂程度的,圈复杂度的概念是由这哥们Thomas J. McCabe, Sr在1976年的时候提出的概念。

1. 为什么需要圈复杂度

如果你现在的项目,代码的可读性非常差,难以维护,单个函数代码特别的长,各种if else  case嵌套,看着大段大段写的糟糕的代码无从下手,甚至到了根本看不懂的地步,那么你可以考虑使用圈复杂度来衡量自己项目中代码的复杂性。

如果不刻意的加以控制,当我们的项目达到了一定的规模之后,某些较为复杂的业务逻辑就会导致有些开发写出很复杂的代码。

举个真实的复杂业务的例子,如果你使用TDD(Test-Driven  Development)的方式进行开发的话,当你还没有真正开始写某个接口的实现的时候,你写的单测可能都已经达到了好几十个case,而真正的业务逻辑甚至还没有开始写

再例如,一个函数,有几百、甚至上千行的代码,除此之外各种if else  while嵌套,就算是写代码的人,可能过几周忘了上下文再来看这个代码,可能也看不懂了,因为其代码的可读性太差了,你读懂都很困难,又谈什么维护性和可扩展性呢?

那我们如何在编码中,CR(Code  Review)中提早的避免这种情况呢?使用圈复杂度的检测工具,检测提交的代码中的圈复杂度的情况,然后根据圈复杂度检测情况进行重构。把过长过于复杂的代码拆成更小的、职责单一且清晰的函数,或者是用设计模式来解决代码中大量的if  else的嵌套逻辑。

可能有的人会认为,降低圈复杂度对我收益不怎么大,可能从短期上来看是这样的,甚至你还会因为动了其他人的代码,触发了圈复杂度的检测,从而还需要去重构别人写的代码。

但是从长期看,低圈复杂度的代码具有更佳的可读性、扩展性和可维护性。同时你的编码能力随着设计模式的实战运用也会得到相应的提升。

2. 圈复杂度度量标准

那圈复杂度,是如何衡量代码的复杂程度的?不是凭感觉,而是有着自己的一套计算规则。有两种计算方式,如下:

节点判定法

点边计算法

判定标准我整理成了一张表格,仅供参考。

圈复杂度 说明

1 - 10 代码是OK的,质量还行

11 - 15 代码已经较为复杂,但也还好,可以设法对某些点重构一下

16 - ∞ 代码已经非常的复杂了,可维护性很低, 维护的成本也大,此时必须要进行重构

当然,我个人认为不能够武断的把这个圈复杂度的标准应用于所有公司的所有情况,要按照自己的实际情况来分析。

这个完全是看自己的业务体量和实际情况来决定的。假设你的业务很简单,而且是个单体应用,功能都是很简单的CRUD,那你的圈复杂度即使想上去也没有那么容易。此时你就可以选择把圈复杂度的重构阈值设定为10.

而假设你的业务十分复杂,而且涉及到多个其他的微服务系统调用,再加上各种业务中的corner case的判断,圈复杂度上100可能都不在话下。

而这样的代码,如果不进行重构,后期随着需求的增加,会越垒越多,越来越难以维护。

2.1 节点判定法

这里只介绍最简单的一种,节点判定法,因为包括有的工具其实也是按照这个算法去算法的,其计算的公式如下。

圈复杂度 = 节点数量 + 1

节点数量代表什么呢?就是下面这些控制节点。

if、for、while、case、catch、与、非、布尔操作、三元运算符

大白话来说,就是看到上面符号,就把圈复杂度加1,那么我们来看一个例子。

图片

我们按照上面的方法,可以得出节点数量是13,那么最终的圈复杂度就等于13 + 1 =  14,圈复杂度是14,值得注意的是,其中的&&也会被算作节点之一。

2.2 使用工具

对于golang我们可以使用Gocognit来判定圈复杂度,你可以使用go get  GitHub.com/uudashr/gocognit/cmd/gocognit快速的安装。然后使用gocognit  $file就可以判断了。我们可以新建文件test.go。

package main

import (

"flag"

"log"

"os"

"sort"

)

func main() {

log.SetFlags(0)

log.SetPrefix("cognitive: ")

flag.Usage = usage

flag.Parse()

args := flag.Args()

if len(args) == 0 {

usage()

}

stats := analyze(args)

sort.Sort(byComplexity(stats))

written := writeStats(os.Stdout, stats)

if *avg {

showAverage(stats)

}

if *over > 0 && written > 0 {

os.Exit(1)

}

}

然后使用命令gocognit test.go,来计算该代码的圈复杂度。

$ gocognit test.go

6 main main test.go:11:1

表示main包的main方法从11行开始,其计算出的圈复杂度是6。

3. 如何降低圈复杂度

这里其实有很多很多方法,然后各类方法也有很多专业的名字,但是对于初了解圈复杂度的人来说可能不是那么好理解。所以我把如何降低圈复杂度的方法总结成了一句话那就是——“尽量减少节点判定法中节点的数量”。

换成大白话来说就是,尽量少写if、else、while、case这些流程控制语句。

其实你在降低你原本代码的圈复杂度的时候,其实也算是一种重构。对于大多数的业务代码来说,代码越少,对于后续维护阅读代码的人来说就越容易理解。

简单总结下来就两个方向,一个是拆分小函数,另一个是想尽办法少些流程控制语句。

3.1 拆分小函数

拆分小函数,圈复杂度的计算范围是在一个function内的,将你的复杂的业务代码拆分成一个一个的职责单一的小函数,这样后面阅读的代码的人就可以一眼就看懂你大概在干嘛,然后具体到每一个小函数,由于它职责单一,而且代码量少,你也很容易能够看懂。除了能够降低圈复杂度,拆分小函数也能够提高代码的可读性和可维护性。

比如代码中存在很多condition的判断。

其实可以优化成我们单独拆分一个判断函数,只做condition判断这一件事情。

图片

3.2 少写流程控制语句

这里举个特别简单的例子。

图片

其实可以直接优化成下面这个样子。

图片

例子就先举到这里,其实你也发现,其实就像我上面说的一样,其目的就是为了减少if等流程控制语句。其实换个思路想,复杂的逻辑判断肯定会增加我们阅读代码的理解成本,而且不便于后期的维护。所以,重构的时候可以想办法尽量去简化你的代码。

那除了这些还有没有什么更加直接一点的方法呢?例如从一开始写代码的时候就尽量去避免这个问题。

4. 使用go-linq

我们先不用急着去了解go-linq是什么,我们先来看一个经典的业务场景问题。

从一个对象列表中获取一个ID列表

如果在go中,我们可以这么做。

图片

略显繁琐,熟悉Java的同学可能会说,这么简单的功能为什么会写的这么复杂,于是三下五除二写下了如下的代码。

图片

上图中使用了Java8的新特性Stream,而Go语言目前还无法达到这样的效果。于是就该轮到go-linq出场了,使用go-linq之后的代码就变成了如下的模样。

图片

怎么样,是不是看到Java 8  Stream的影子,重构之后的代码我们暂且不去比较行数,从语意上看,同样的清晰直观,这就是go-linq,我们用了一个例子来为大家介绍了它的定义,接下来简单介绍几种常见的用法,这些都是官网上给的例子。

4.1 ForEach

与Java 8中的foreach是类似的,就是对集合的一个遍历。

图片

首先是一个From,这代表了输入,梦开始的地方,可以和Java 8中的stream划等号。

然后可以看到有ForEach和ForEachT,ForEachIndexed和ForEachIndexedT。前者是只遍历元素,后者则将其下标也一起打印了出来。跟Go中的Range是一样的,跟Java  8的ForEach也类似,但是Java  8的ForEach没有下标,之所以go-ling有,是因为它自己记录了一个index,ForEachIndexed源码如下。

图片

其中两者的区别是啥呢?我认识是你对你要遍历的元素的类型是否敏感,其实大多数情况应该都是敏感的。如果你使用了带T的,那么在遍历的时候go-ling会将interface转成你在函数中所定义的类型,例如fruit  string。

否则的话,就需要我们自己去手动的将interface转换成对应的类型,所以后续的所有的例子我都会直接使用ForEachT这种类型的函数。

4.2 Where

可以理解为sql中的where条件,也可以理解为Java 8中的filter,按照某些条件对集合进行过滤。

图片

上面的Where筛选出了字符串长度大于6的元素,可以看到其中有个ToSlice,就是将筛选后的结果输出到指定的slice中。

4.3 Distinct

与你所了解到的Mysql中的Distinct,又或者是Java 8中的Distinct是一样的作用,去重。

4.3.1 简单场景

4.3.2 复杂场景

当然,实际的开发中,这种只有一个整形数组的情况是很少的,大部分需要判断的对象都是一个struct数组。所以我们再来看一个稍微复杂一点的例子。

图片

上面的代码是对一个products的slice,根据product的Code字段来进行去重。

4.4 Except

对两个集合做差集。

4.4.1 简单场景图片

4.4.2 复杂场景图片

4.5 Intersect

对两个集合求交集。

4.5.1 简单场景图片

4.5.2 复杂场景图片

4.6 Select

从功能上来看,Select跟ForEach是差不多的,区别如下。

Select 返回了一个Query对象

ForEach 没有返回值

在这里你不用去关心Query对象到底是什么,就跟Java8中的map、filter等等控制函数都会返回Stream一样,通过返回Query,来达到代码中流式编程的目的。

4.6.1 简单场景

图片

select简单场景

其中SelectT就是遍历了一个集合,然后做了一些运算,将运算之后的结果输出到了新的slice中。

SelectMany为集合中的每一个元素都返回一个Query,跟Java  8中的flatMap类似,flatMap则是为每个元素创建一个Stream。简单来说就是把一个二维数组给它拍平成一维数组。

4.6.2 复杂场景图片

4.7 Group图片

Group根据指定的元素对结合进行分组,Group`的源码如下。

图片

Key就是我们分组的时候用key,Group就是分组之后得到的对应key的元素列表。

好了,由于篇幅的原因,关于go-linq的使用就先介绍到这里,感兴趣的可以去go-linq官网查看全部的用法。

5. 关于go-linq的使用

首先我认为使用go-linq不仅仅是为了“逃脱”检测工具对圈复杂度的检查,而是真正的通过重构自己的代码,让其变的可读性更佳。

举个例子,在某些复杂场景下,使用go-linq反而会让你的代码更加的难以理解。代码是需要给你和后续维护的同学看的,不要盲目的去追求低圈复杂度的代码,而疯狂的使用go-linq。

我个人其实只倾向于使用go-linq对集合的一些操作,其他的复杂情况,好的代码,加上适当的注释,才是不给其他人(包括你自己)挖坑的行为。而且并不是说所有的if  else都是烂代码,如果必要的if else能够大大增加代码的可读性,何乐而不为?(这里当然说的不是那种满屏各种if else前套的代码)

到此,相信大家对“怎么降低代码的圈复杂度”有了更深的了解,不妨来实际操作一番吧!这里是编程网网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

--结束END--

本文标题: 怎么降低代码的圈复杂度

本文链接: https://lsjlt.com/news/84115.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • 怎么降低代码的圈复杂度
    本篇内容主要讲解“怎么降低代码的圈复杂度”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“怎么降低代码的圈复杂度”吧!0. 什么是圈复杂度可能你之前没有听说过这个词...
    99+
    2024-04-02
  • GO怎么降低圈复杂度
    这篇“GO怎么降低圈复杂度”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“GO怎么降低圈复杂度”文章吧。对业务函数需要做基本的...
    99+
    2023-07-04
  • JavaScript重构技巧中如何降低函数复杂度
    这篇文章给大家介绍JavaScript重构技巧中如何降低函数复杂度,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。JavaScript 是一种易于学习的编程语言,编写运行并执行某些操作的...
    99+
    2024-04-02
  • oracle怎么设置密码复杂度
    在Oracle数据库中,可以通过以下步骤来设置密码复杂度: 使用管理员权限登录到Oracle数据库。 运行以下SQL语句查看...
    99+
    2024-05-21
    oracle
  • 怎么计算并测量ABAP及Java代码的环复杂度
    这篇文章主要介绍“怎么计算并测量ABAP及Java代码的环复杂度”,在日常操作中,相信很多人在怎么计算并测量ABAP及Java代码的环复杂度问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”怎么计算并测量ABAP...
    99+
    2023-06-04
  • PHP中封装性的代码复杂度管理
    封装性是面向对象编程(OOP)的核心概念之一,它能够提高代码的可维护性和可复用性。然而,在实际开发中,过于复杂的封装也可能会带来一些问题。本文将介绍如何管理PHP代码中的封装性复杂度,并提供一些具体的代码示例。控制类的大小类应该有明确的职责...
    99+
    2023-10-21
    管理 代码复杂度 PHP封装性
  • 大量内存占用会降低无关代码的执行速度
    亲爱的编程学习爱好者,如果你点开了这篇文章,说明你对《大量内存占用会降低无关代码的执行速度》很感兴趣。本篇文章就来给大家详细解析一下,主要介绍一下,希望所有认真读完的童鞋们,都有实质性的提高。问题内...
    99+
    2024-04-04
  • Linux中怎么设置密码复杂度
    本篇文章给大家分享的是有关Linux中怎么设置密码复杂度,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。在大多数 Linux 系统中,我们可以用 PAM(可插拔认证模块plugg...
    99+
    2023-06-16
  • linux密码复杂度策略怎么配置
    要配置Linux密码复杂度策略,您可以按照以下步骤进行操作: 打开`/etc/login.defs`文件: sudo vi /e...
    99+
    2023-10-25
    linux
  • PHP 运算符秘籍:破解代码复杂度
    算术运算符 算术运算符用于执行基本的数学运算,如加 (+)、减 (-)、乘 (*) 和除 (/)。这些运算符优先级较低,这意味着它们在关系运算符和赋值运算符之后执行。例如: $num1 = 10; $num2 = 5; $result =...
    99+
    2024-04-02
  • ASP中的类:解码分离代码复杂度的制胜法宝
    【】: ASP 中的类是一种重要的编程技术,它可以帮助我们创建更加结构化和易于维护的代码。然而,随着代码变得越来越复杂,管理和维护这些类也变得越来越困难。这时,分离代码复杂度就变得尤为重要。 分离代码复杂度是指将大型、复杂的类分解成多个较...
    99+
    2024-02-26
    【文章】:ASP;类;分离代码复杂度;可维护性;可读性。
  • 优化代码:降低回流和重绘的方法
    篇一:精简代码实现:减少回流和重绘的技巧 在开发网页应用时,优化性能是一个重要的任务。其中,减少页面回流(reflow)和重绘(repaint)是提高网页性能的关键点之一。本文将分享一些技巧和具体的代码示例,帮助你更好地减少回流...
    99+
    2024-01-26
    可以减少回流次数
  • PHP开发中如何优化代码复杂度和耦合度
    在PHP开发中,代码的复杂度和耦合度是我们需要关注和优化的重要问题。高复杂度的代码往往难以理解和维护,而高耦合度的代码则会增加修改和扩展的困难。下面将介绍一些常用的技术和方法来优化代码的复杂度和耦合度,并提供一些具体的代码示例。使用设计模式...
    99+
    2023-10-21
    模块化 代码复杂度 优化:性能 耦合度 代码复杂度:简洁
  • python简单批量梯度下降代码怎么写
    python简单批量梯度下降代码怎么写,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。简单批量梯度下降代码其中涉及到公式alpha表示超参数,由外部设定。过大则会出现震荡现象,过...
    99+
    2023-06-26
  • 亚马逊服务器怎么降低存储速度
    1. 了解亚马逊服务器存储速度 在降低亚马逊服务器存储速度之前,我们需要了解存储速度是什么以及它对服务器的影响。存储速度是指服务器存储数据的速度,通常以每秒读写操作的数量来衡量。存储速度越快,服务器处理数据的速度就越快,但也会增加服务器的...
    99+
    2023-10-27
    亚马逊 速度 服务器
  • web算法的时间复杂度和空间复杂度是什么
    这篇文章主要介绍了web算法的时间复杂度和空间复杂度是什么的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇web算法的时间复杂度和空间复杂度是什么文章都会有所收获,下面我们一起来...
    99+
    2024-04-02
  • 怎么用Python检验用户输入密码的复杂度
    这篇文章主要讲解了“怎么用Python检验用户输入密码的复杂度”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“怎么用Python检验用户输入密码的复杂度”吧!密码强度检测规则:至少包含一个数字...
    99+
    2023-07-05
  • 亚马逊服务器怎么降低存储速度呢
    S3可以提供多种不同的存储选项,包括MySQL、MongoDB、Redis、Cassandra和Kubernetes等。它还可以根据应用程序的需要自动调整存储空间,以确保最佳性能和吞吐量。 此外,S3还支持缓存技术,可以将数据预先缓存到内...
    99+
    2023-10-27
    亚马逊 速度 服务器
  • 亚马逊服务器怎么降低存储速度的方法
    使用云存储服务:亚马逊的云存储服务Amazon S3可以自动化数据备份、重复数据删除和同步,从而大大降低存储成本。 使用虚拟化技术:虚拟化可以将多个物理服务器合并为一个虚拟服务器,从而减少硬件资源的消耗,并提高存储效率。 优化数据库:对于...
    99+
    2023-10-27
    亚马逊 速度 服务器
  • 低代码平台服务编排提升效率、降低成本的新方式
    低代码平台服务编排是一种新兴的技术,它通过使用图形化的界面和拖拽式的操作,让用户能够快速、高效地创建和部署应用程序。这种方式不仅大大提高了开发效率,也降低了开发成本。本文将详细说明低代码平台服务编排的工作原理和优势。 一、低代码平台服务编排...
    99+
    2023-12-17
    降低成本 效率 代码
软考高级职称资格查询
推荐阅读
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作