博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
圈复杂度和代码质量优化(附带示例代码纠正代码质量)
阅读量:6829 次
发布时间:2019-06-26

本文共 4108 字,大约阅读时间需要 13 分钟。

  hot3.png

什么是圈复杂度?

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

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

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

  • 从1开始,一直往下通过程序。

  • 一但遇到以下关键字,或者其它同类的词,就加1:if,while,repeat,for,and,or。

  • 给case语句中的每一种情况都加1。

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

def add(a, b):    return a + b

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

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

pip install mccabe

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

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为例,下面一样):

function test($number){	  if($number < self::MIN_NUMBER)  {    $number = self::MIN_NUMBER;  }  for($i = 0; $i < $number; $i++){    //some code	  }}

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

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.替换算法(把复杂算法替换为另一个更清晰的算法

if($str == 'China'){  $result = '中国人';}else if($str == 'US'){  $result = '美国人';}else if($str == 'France'){  $result = '法国人';}

变成这样:

$people = [  'China' => '中国人',  'US' => '美国人',  'France' => '法国人'];$result = $people[$str];

 

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

if((条件1 && 条件2) || !条件1){  return true;}else{  return false;}

变成这样:

if(条件1 && !条件2){  return false;}return true;

 

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

if(do_some_1($number) || do_some_2($number)){  $number = $number.$someStr1.$someStr2.'123456789';}else{  $number = $number.$someStr3.$someStr4.'123456789';}

变成这样:

if(do_some_fun($number)){  $number = do_some_fun1($number);}else{  $number = do_some_fun2($number);}

 

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

if($x < 1) return 0;if($y > 10) return 0;if($z != 0) return 0;

变成这样:

if(get_result($x,$y,$z)) return 0;

 

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

$bool = false;foreach($arrs as $arr){    if(!$bool){        if($arr == 1){            someFunction();            $bool = true;        }        if($arr == 2){            someFunction();            $bool = true;        }    }}

变成这样:

foreach($arrs as $arr){    if($arr == 1 || $arr == 2){        someFunction();    }    break;}

 

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

switch ($cat){    case ‘fish’:        eatFish();    case ‘moss’:        eatMoss();}function eatFish() {    echo "Whale eats fish";}function eatMoss() {    echo "Whale eat moss";}

变成这样:

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.参数化方法(建立单一函数,以参数表达那些不同的值):

$result = min(lastUsage(), 100) * 0.03;if(lastUsage() > 100){    $result += (min(lastUsage(), 200) - 100) * 0.05;}

变成这样:

$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.明确函数取代参数(针对该参数的每一个可能值,建立一个独立函数):

if($name == 'width'){    $width = $value;}else if ($name == 'height'){    $height = $value;}

变成这样:

function setWidth($value){    $width = $value;}function setHeight($value){    $height = $value;}

 

参考视频:

转载于:https://my.oschina.net/hjchhx/blog/1840978

你可能感兴趣的文章
golang 介绍以及踩坑之四
查看>>
Shiro-集成验证码
查看>>
最全Drawable基础总结
查看>>
(十六)java版电子商务spring cloud分布式微服务b2b2c社交电商-用restTemplate消费服务...
查看>>
小猿圈学习Web前端需要掌握哪些内容?
查看>>
ubuntu 下安装apache+php+mysql
查看>>
eclipse freemarker 插件 地址
查看>>
Kinect for windows中的抓握(Grip)和释放(GripRelease)
查看>>
提高局域网内网速的几个小技巧
查看>>
Left4Dead2's wound
查看>>
Gulp自动压缩、合并文件并在引用文件的地方加hash
查看>>
好产品,从准确把握用户需求开始——卢云飞
查看>>
c++中的双向链表写法,主要实现(增删查改,链表逆置,构造函数,运算符重载,等)...
查看>>
Eclipse 代码格式化
查看>>
android——SharedPreferences存放数据
查看>>
2018-08-07 期 MapReduce模拟实现热销商品排行
查看>>
JavaEE的13种核心技术
查看>>
JEPLUS之如何快速复制表——JEPLUS软件快速开发平台
查看>>
前端面试题目大全
查看>>
打包Android项目
查看>>