Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >圈复杂度和代码质量优化(附带示例代码纠正代码质量)

圈复杂度和代码质量优化(附带示例代码纠正代码质量)

作者头像
NateHuang
发布于 2019-03-12 09:24:53
发布于 2019-03-12 09:24:53
7.1K01
代码可运行
举报
文章被收录于专栏:开发经验记录开发经验记录
运行总次数:1
代码可运行

什么是圈复杂度?

———————————————————————————————————————

圈复杂度(Cyclomatic Complexity)是衡量计算机程序复杂程度的一种措施。它根据程序从开始到结束的线性独立路径的数量计算得来的。

圈复杂度越高,代码就越难复杂难维护。坑就越大。。。

  • 从1开始,一直往下通过程序。
  • 一但遇到以下关键字,或者其它同类的词,就加1:if,while,repeat,for,and,or。
  • 给case语句中的每一种情况都加1。

例如下面这个函数,圈复杂度为1,意味着代码只有一条路径。:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
def add(a, b):
    return a + b

对于有一条分支的代码,它的圈复杂度为 2 ,比如下面递归计算阶乘的代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
def factorial(n):
  if n == 0:
    return 1
  else:
    return n * factorial(n-1)

它的计算方法很简单:

计算公式1:V(G)=E-N+2P。其中,E表示控制流图中边的数量,N表示控制流图中节点的数量,P图的连接组件数目(图的组件数是相连节点的最大集合)。因为控制流图都是连通的,所以P为1.

圈复杂度

代码状况

可测性

维护成本

1-10

清晰、结构化

11-20

复杂

21-30

非常复杂

>30

不可读

不可测

非常高

如何测量程序的圈复杂度?

———————————————————————————————————————

Python 中可以使用 mccabe 包测量程序的圈复杂度。

只需要很简单的一行命令即可安装mccabe

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
pip install mccabe

运行下面这行命令,就可以检测test.py的圈复杂度

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
python -m mccabe --min 5 test.py

其中 --min 5 是指最小允许的圈复杂度,高于5的圈复杂度则输出出来,如下图:

第一个输出的结果是,91行的roundRobin函数,复杂度为7.

除了mccabe,现在市场上也有很多检测圈复杂度工具

工具

类型

系统平台

扫描语言

PMD/Checkstyle

免费

Windows/Linux/Mac

Java,JS

OClint

免费

Mac

OC

Coverity

商业

Windows/Linux/Mac

C/C++,Java,C#,OC/C++,JS,Python,Ruby,PHP

SourceMonitor

免费

Windows

C/C++,C#,VB.NET,Java,Delphi,VB6,HTML

CCM

免费

Windows

JS,C/C+,C#

HFCCA

免费

Windows/Linux/Mac

C/C++,OC

Lizard

免费

Windows/Linux/Mac

C/C++,Java,C#,JS,OC/C++,Swift,Python,Ruby,TTCN-3,PHP,Scala,GDScript

代码质量优化

———————————————————————————————————————

把子程序的一部分提取成另一个子程序,不会降低整个程序的复杂度,只是把决策点移到其他地方,但是这样做可以降低你在同一时间必须关注的复杂度水平。由于重点是要降低你需要在头脑中同时考虑的项目的数量,所以降低一个给定程序的复杂度是有价值的。

1.提炼函数(php为例,下面一样):

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function test($number){	
  if($number < self::MIN_NUMBER)
  {
    $number = self::MIN_NUMBER;
  }
  for($i = 0; $i < $number; $i++){
    //some code	
  }
}

可以替换成下面这种模式:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function test($number){	
  $number = getMin($number);
  for($i = 0; $i < $number; $i++){
    //some code	
  }
}
function getMin($number){
  if($number < self::MIN_NUMBER){
    return self::MIN_NUMBER;
  }
  return $number
}

2.替换算法(把复杂算法替换为另一个更清晰的算法):

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
if($str == 'China'){
  $result = '中国人';
}
else if($str == 'US'){
  $result = '美国人';
}
else if($str == 'France'){
  $result = '法国人';
}

变成这样:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$people = [
  'China' => '中国人',
  'US' => '美国人',
  'France' => '法国人'
];
$result = $people[$str];

3.逆向表达(调换条件表达顺序达到简化复杂度):

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
if((条件1 && 条件2) || !条件1){
  return true;
}
else{
  return false;
}

变成这样:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
if(条件1 && !条件2){
  return false;
}
return true;

4.分解条件(对复杂条件表达式(if、else)进行分解并提取成独立函数):

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
if(do_some_1($number) || do_some_2($number)){
  $number = $number.$someStr1.$someStr2.'123456789';
}
else{
  $number = $number.$someStr3.$someStr4.'123456789';
}

变成这样:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
if(do_some_fun($number)){
  $number = do_some_fun1($number);
}
else{
  $number = do_some_fun2($number);
}

5.合并条件(将这些判断合并为一个条件式,并提取成独立函数):

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
if($x < 1) return 0;
if($y > 10) return 0;
if($z != 0) return 0;

变成这样:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
if(get_result($x,$y,$z)) return 0;

6.移除控制标记(可以使用break和return取代控制标记。):

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$bool = false;
foreach($arrs as $arr){
    if(!$bool){
        if($arr == 1){
            someFunction();
            $bool = true;
        }
        if($arr == 2){
            someFunction();
            $bool = true;
        }
    }
}

变成这样:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
foreach($arrs as $arr){
    if($arr == 1 || $arr == 2){
        someFunction();
    }
    break;
}

7.以多态取代条件式(将整个条件式的每个分支放进一个子类的重载方法中,然后将原始函数声明为抽象方法。由于php是弱类型语言,这里体现的有点模糊):

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
switch ($cat){
    case ‘fish’:
        eatFish();
    case ‘moss’:
        eatMoss();
}
function eatFish() {
    echo "Whale eats fish";
}
function eatMoss() {
    echo "Whale eat moss";
}

变成这样:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
interface Eat {
    function eatFish();  
    function eatMoss();
}

class Whale implements Eat {
    public function eatFish() {
        echo "Whale eats fish";
    }
    public function eatMoss() {
        echo "Whale eat moss";
    }
}

8.参数化方法(建立单一函数,以参数表达那些不同的值):

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$result = min(lastUsage(), 100) * 0.03;
if(lastUsage() > 100){
    $result += (min(lastUsage(), 200) - 100) * 0.05;
}

变成这样:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$result = getMin(0,100) * 0.03;
$result += getMin(100,200) * 0.03;

function getMin($start, $end){
    if(lastUsage() > $start){
        return (min(lastUsage(),$end) - $start);
    }
    return 0;
}

9.明确函数取代参数(针对该参数的每一个可能值,建立一个独立函数):

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
if($name == 'width'){
    $width = $value;else if ($name == 'height'){
    $height = $value;
}

变成这样:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function setWidth($value){
    $width = $value;
}
function setHeight($value){
    $height = $value;
}

参考视频:谷歌:简洁代码之道

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2018/07/05 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
[最全算法总结]我是如何将递归算法的复杂度优化到O(1)的
相信提到斐波那契数列,大家都不陌生,这个是在我们学习 C/C++ 的过程中必然会接触到的一个问题,而作为一个经典的求解模型,我们怎么能少的了去研究这个模型呢?笔者在不断地学习和思考过程中,发现了这类经典模型竟然有如此多的有意思的求解算法,能让这个经典问题的时间复杂度降低到 \(O(1)\) ,下面我想对这个经典问题的求解做一个较为深入的剖析,请听我娓娓道来。
Angel_Kitty
2019/07/17
1.5K0
代码质量第 3 层 - 可读的代码
可读的代码能极大的提高开发效率。在开发的过程中,有很大一部分时间是在阅读代码。可读的代码,容易理解,也容易改。反之,不可读性的代码,读起来心情很差,改起来也容易出错。
社区小番茄
2022/01/12
9856
代码质量第 3 层 - 可读的代码
算法复杂度分析
为什么要进行算法分析? 预测算法所需的资源 计算时间(CPU 消耗) 内存空间(RAM 消耗) 通信时间(带宽消耗) 预测算法的运行时间 在给定输入规模时,所执行的基本操作数量。 或者称为算法复杂度(Algorithm Complexity) 如何衡量算法复杂度? 内存(Memory) 时间(Time) 指令的数量(Number of Steps) 特定操作的数量 磁盘访问数量 网络包数量 渐进复杂度(Asymptotic Complexity) 算法的运行时间与什么相关? 取决于输入的数据。(例如:如果
前朝楚水
2018/04/02
1K0
算法复杂度分析
【数据结构初阶】八大排序算法+时空复杂度
1.直接插入排序思想: 假设现在已经有一个有序序列,如果有一个数字插入到这段序列的末尾,我们会选择拿这个数和它前面的每个数字都比较一遍,如果前面的数字比他大,那我们就让前面的数字赋值到这个被插入的数字位置,依次与前面的数字进行比较,最后我们把插入有序序列的数字放到他应该在的位置
举杯邀明月
2023/04/12
1.6K0
【数据结构初阶】八大排序算法+时空复杂度
代码质量与技术债系列分享之一—如何做好CodeReview
在今年的敏捷团队建设中,我通过Suite执行器实现了一键自动化单元测试。Juint除了Suite执行器还有哪些执行器呢?由此我的Runner探索之旅开始了!
京东技术
2024/04/11
2160
代码质量与技术债系列分享之一—如何做好CodeReview
LeetCode 题目解答——155~226 题
[Updated on 9/22/2017] 如今回头看来,里面很多做法都不是最佳的,有的从复杂度上根本就不是最优解,有的写的太啰嗦,有的则用了一些过于 tricky 的方法。我没有为了这个再更新,就让它们去吧。
四火
2022/07/19
7030
LeetCode 题目解答——155~226 题
用Js怒刷LeetCode
针对有一定数据结构基础(了解链表, 二叉树, 二叉堆, 递归)的基本概念,并对时间空间复杂度有基本认知的。
hellocoder2028
2022/10/27
2.2K0
小白看React Native
本文介绍了React Native技术栈,从React Native简介、React Native核心组件、React Native生命周期、React Native的props和state、React Native的调试、React Native的性能优化、React Native的第三方库、React Native的跨平台、React Native的社区等方面进行了介绍。同时,还通过实例介绍了React Native的代码结构、React Native的代码风格、React Native的代码规范、React Native的代码评审。最后,总结了React Native的常见问题以及解决方案,并介绍了学习React Native的资源推荐。
MelonTeam
2018/01/04
2.1K0
小白看React Native
详解圈复杂度
圈复杂度(Cyclomatic complexity,简写CC)也称为条件复杂度,是一种代码复杂度的衡量标准。由托马斯·J·麦凯布(Thomas J. McCabe, Sr.)于1976年提出,用来表示程序的复杂度,其符号为VG或是M。它可以用来衡量一个模块判定结构的复杂程度,数量上表现为独立现行路径条数,也可理解为覆盖所有的可能情况最少使用的测试用例数。圈复杂度大说明程序代码的判断逻辑复杂,可能质量低且难于测试和 维护。程序的可能错误和高的圈复杂度有着很大关系。
BUG弄潮儿
2021/11/12
6.3K0
详解圈复杂度
前端代码质量-圈复杂度原理和实践
针对上面的问题,本文的主角 圈复杂度 重磅登场,本文将从圈复杂度原理出发,介绍圈复杂度的计算方法、如何降低代码的圈复杂度,如何获取圈复杂度,以及圈复杂度在公司项目的实践应用。
ConardLi
2019/10/24
2K0
降低代码的圈复杂度
可能你之前没有听说过这个词,也会好奇这是个什么东西是用来干嘛的,在维基百科上有这样的解释。
SH的全栈笔记
2022/08/17
1.4K0
降低代码的圈复杂度
[ JavaScript ] 代码圈复杂度优化
圈复杂度就是可以用来衡量一个模块判定结构的复杂程度,数量上表现为独立线性路径条数。举一个最简单的例子,一个函数有 if else 语句,这个时候,执行这个函数就需要两条路径来执行,一个是 if 另一个是 else,那么,这个函数的圈复杂度就为 2 。
GavinUI
2021/03/26
2.2K0
[ JavaScript ] 代码圈复杂度优化
重构指标之如何监控代码圈复杂度
Tech 导读 随着业务需求不断迭代,项目代码不断更新,开发人员会考虑代码的可测试性,倾向于编写简单的代码。所以代码圈复杂度是衡量工程代码是否适时重构的重要指标之一。本文意在分享基于python三方库提供一种自动监控工程代码圈复杂度的落地方案。 01
京东技术
2023/09/21
5240
重构指标之如何监控代码圈复杂度
代码质量第 3 层 - 可读的代码
可读的代码能极大的提高开发效率。在开发的过程中,有很大一部分时间是在阅读代码。可读的代码,容易理解,也容易改。反之,不可读性的代码,读起来心情很差,改起来也容易出错。
前端GoGoGo
2021/12/02
5420
什么是圈复杂度?如何降低圈复杂度?
在软件开发中,代码的复杂性是一个重要的考量因素。圈复杂度是一种用于衡量代码复杂性的指标,它可以帮助开发者评估代码的可读性、可维护性和可测试性。本文将详细介绍圈复杂度的概念,并提供几种降低圈复杂度的方法。同时,我们还将探讨如何在前端开发中使用ESLint和VS Code工具来设置和检测圈复杂度。
can4hou6joeng4
2023/11/16
1.1K0
【C++11】消除重复, 提升代码质量---type_tratis
为了解决因为代码圈复杂度产生的代码质量问题,C++11提供了type_tratis类型萃取功能,在一定程度上可以消除冗长的代码分支语句,降低圈复杂度进而提升代码的可维护性。
CPP开发前沿
2021/11/16
1.7K0
移动端arm cpu优化学习笔记第2弹--常量阶时间复杂度中值滤波
https://github.com/Ldpe2G/ArmNeonOptimization/tree/master/ConstantTimeMedianFilter
Ldpe2G
2019/10/24
1.2K0
移动端arm cpu优化学习笔记第2弹--常量阶时间复杂度中值滤波
js对象和类的操作
深度拷贝最主要需要考虑的因素就是需要考虑js的各种数据类型 1)6种基本类型(number,string,null,undefined,boolean,symbol)不需要处理,直接复制返回即可 2)几种特殊类型 date、regexp、set、map,直接new一遍即可 3)需要着重处理的类型 Array、Object,直接使用递归处理即可 4)递归处理Array、Object的过程中需要考虑循环引用,循环引用处理可以利用WeakMap将每次递归的对象存储起来,如果一样,直接返回
epoos
2022/06/06
2.4K0
js对象和类的操作
干货 | Trip.com Flutter代码质量探索
Kui,携程移动端高级软件工程师,专注于移动端开发,热衷于移动端跨平台技术的研究和实践。
携程技术
2021/12/27
2.3K0
干货 | Trip.com Flutter代码质量探索
数据结构设计题
十万个为什么 What to return for each function? Size of data? 在做题之前就clearify(功能,use case,function的input和ret
王脸小
2019/10/28
1.1K0
相关推荐
[最全算法总结]我是如何将递归算法的复杂度优化到O(1)的
更多 >
领券
社区富文本编辑器全新改版!诚邀体验~
全新交互,全新视觉,新增快捷键、悬浮工具栏、高亮块等功能并同时优化现有功能,全面提升创作效率和体验
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验