#圈复杂度

来源:互联网 发布:权力的游戏第八季 知乎 编辑:程序博客网 时间:2024/04/28 14:52

##概念

循环复杂度(Cyclomatic complexity)也称为条件复杂度,是一种软件度量,是由老托马斯·J·麦凯布(英语:Thomas J. McCabe, Sr.) 在1976年提出,用来表示程序的复杂度,其符号为VG或是M。“循环复杂度”的名称有时会让人误解,因为此复杂度不只计算程序中的循环 (循环)个数,也包括条件及分支个数。


##算法

圈复杂度(Cyclomatic Complexity)是一种代码复杂度的衡量标准。它可以用来衡量一个模块判定结构的复杂程度,数量上表现为独立现行 路径条数,也可理解为覆盖所有的可能情况最少使用的测试用例数。圈复杂度大说明程序代码的判断逻辑复杂,可能质量低且难于测试和 维护。程序的可能错误和高的圈复杂度有着很大关系。

它的计算方法很简单,计算公式为:V(G)=e-n+2。其中,e表示控制流图中边的数量,n表示控制流图中节点的数量。其实,圈复杂度的计 算还有更直观的方法,因为圈复杂度所反映的是“判定条件”的数量,所以圈复杂度实际上就是等于判定节点的数量再加上1,也即控制流 图的区域数,对应的计算公式为:V(G)=区域数=判定节点数+1。

对于多分支的CASE结构或IF-ELSEIF-ELSE结构,统计判定节点的个数时需要特别注意一点,要求必须统计全部实际的判定节点数,也即每 个ELSEIF语句,以及每个CASE语句,都应该算为一个判定节点。判定节点在模块的控制流图中很容易被识别出来,所以,针对程序的控制 流图计算圈复杂度V(G)时,最好还是采用第一个公式,也即V(G)=e-n+2;而针对模块的控制流图时,可以直接统计判定节点数,这样更为 简单。


##意义

  • 在缺陷成为缺陷之前 捕获它们。
  • 研究显示,平均每人在其大脑中大约能够处理 7(±2)位数字。这就是为什么大多数人可以很容易地记住电话号码,但却很难记住大 于 7 位数字的信用卡号码、发射次序和其他数字序列的原因。
  • 过去几年的各种研究已经确定:圈复杂度(或 CC)大于 10 的方法存在很大的出错风险。
  • 许多研究发现循环复杂度和缺陷个数有高度的正相关:循环复杂度最高的模组及方法,其中的缺陷个数也最多。
  • 圈复杂度是代码复杂度的一个好的指示器;此外,它还是用于开发人员测试的一个极好的衡量器。一个好的经验法则是创建数量与将被 测试代码的圈复杂度值相等的测试用例。
  • 在持续集成环境中,可以随时间变化评估方法的复杂度和成长度。如果某一方法的 CC 值在不断增长,那么您有两个响应选择:
    • 确保相关测试的健康情况仍然表现为减少风险。
    • 评估重构方法减少任何长期维护问题的可能性。
  • 因为圈复杂度是如此好的一个代码复杂度指示器,所以测试驱动的开发 (test-driven development) 和低 CC 值之间存在着紧密相关 的联系。在编写测试时,开发人员通常倾向于编写不太复杂的代码,因为复杂的代码难以测试。如果您发现自己难以编写某一代码,那么 这是一种警示,表示正在测试的代码可能很复杂。在这些情况下,TDD 的简短的 “代码、测试、代码、测试” 循环将导致重构,而这将 继续驱使非复杂代码的开发。
  • 在使用遗留代码库的情况下,测量圈复杂度特别有价值。
  • 有助于分布式开发团队监视 CC 值,甚至对具有各种技术级别的大型团队也是如此。确定代码库中类方法的 CC 并连续监视这些值将使 您的团队在复杂问题出现时抢先处理它们。

##示例

  • 圈复杂度为 2
public String case1(int num) {    String string = null;    if (num == 1) {        string = "String";    }    return string.substring(0);}
  • 圈复杂度为 6
public String case2(int index, String string) {    String returnString = null;    if (index < 0) {         throw new IndexOutOfBoundsException("exception <0 ");    }    if (index == 1) {         if (string.length() < 2) {             return string;         }       returnString = "returnString1";    } else if (index == 2) {         if (string.length() < 5) {             return string;       }       returnString = "returnString2";    } else {         throw new IndexOutOfBoundsException("exception >2 ");    }    return returnString;}

##PHPMD

PHP Mess Detector是一种代码质量检查工具,支持5大类31小类的质量检查:

  1. Code Size Rules
    1. CyclomaticComplexity: Complexity is determined by the number of decision points in a method plus one for the method entry. The decision points are 'if', 'while', 'for', and 'case labels'. Generally, 1-4 is low complexity, 5-7 indicates moderate complexity, 8-10 is high complexity, and 11+ is very high complexity.
    2. NPathComplexity
    3. ExcessiveMethodLength
    4. ExcessiveClassLength
    5. ExcessiveParameterList
    6. ExcessivePublicCount
    7. TooManyFields
    8. TooManyMethods
    9. ExcessiveClassComplexity
  2. Controversial Rules
    1. Superglobals
    2. CamelCaseClassName
    3. CamelCasePropertyName
    4. CamelCaseMethodName
    5. CamelCaseParameterName
    6. CamelCaseVariableName
  3. Design Rules
    1. ExitExpression
    2. EvalExpression
    3. GotoStatement
    4. NumberOfChildren
    5. DepthOfInheritance
    6. CouplingBetweenObjects
  4. Naming Rules
    1. ShortVariable
    2. LongVariable
    3. ShortMethodName
    4. ConstructorWithNameAsEnclosingClass
    5. ConstantNamingConventions
    6. BooleanGetMethodName
  5. Unused Code Rules
    1. UnusedPrivateField
    2. UnusedLocalVariable
    3. UnusedPrivateMethod
    4. UnusedFormalParameter

##用重构降低圈复杂度

从Refactoring网站看到的93种重构方式,也可学习《重构:改善既有代码的设计》:

  1. Add Parameter
  2. Change Bidirectional Association to Unidirectional
  3. Change Reference to Value
  4. Change Unidirectional Association to Bidirectional
  5. Change Value to Reference
  6. Collapse Hierarchy
  7. Consolidate Conditional Expression
  8. Consolidate Duplicate Conditional Fragments
  9. Convert Dynamic to Static Construction by Gerard M. Davison
  10. Convert Static to Dynamic Construction by Gerard M. Davison
  11. Decompose Conditional
  12. Duplicate Observed Data
  13. Eliminate Inter-Entity Bean Communication (Link Only)
  14. Encapsulate Collection
  15. Encapsulate Downcast
  16. Encapsulate Field
  17. Extract Class
  18. Extract Interface
  19. Extract Method
  20. Extract Package by Gerard M. Davison
  21. Extract Subclass
  22. Extract Superclass
  23. Form Template Method
  24. Hide Delegate
  25. Hide Method
  26. Hide presentation tier-specific details from the business tier (Link Only)
  27. Inline Class
  28. Inline Method
  29. Inline Temp
  30. Introduce A Controller (Link Only)
  31. Introduce Assertion
  32. Introduce Business Delegate (Link Only)
  33. Introduce Explaining Variable
  34. Introduce Foreign Method
  35. Introduce Local Extension
  36. Introduce Null Object
  37. Introduce Parameter Object
  38. Introduce Synchronizer Token (Link Only)
  39. Localize Disparate Logic (Link Only)
  40. Merge Session Beans (Link Only)
  41. Move Business Logic to Session (Link Only)
  42. Move Class by Gerard M. Davison
  43. Move Field
  44. Move Method
  45. Parameterize Method
  46. Preserve Whole Object
  47. Pull Up Constructor Body
  48. Pull Up Field
  49. Pull Up Method
  50. Push Down Field
  51. Push Down Method
  52. Reduce Scope of Variable by Mats Henricson
  53. Refactor Architecture by Tiers (Link Only)
  54. Remove Assignments to Parameters
  55. Remove Control Flag
  56. Remove Double Negative by Ashley Frieze and Martin Fowler
  57. Remove Middle Man
  58. Remove Parameter
  59. Remove Setting Method
  60. Rename Method
  61. Replace Array with Object
  62. Replace Assignment with Initialization by Mats Henricson
  63. Replace Conditional with Polymorphism
  64. Replace Conditional with Visitor by Ivan Mitrovic
  65. Replace Constructor with Factory Method
  66. Replace Data Value with Object
  67. Replace Delegation with Inheritance
  68. Replace Error Code with Exception
  69. Replace Exception with Test
  70. Replace Inheritance with Delegation
  71. Replace Iteration with Recursion by Dave Whipp
  72. Replace Magic Number with Symbolic Constant
  73. Replace Method with Method Object
  74. Replace Nested Conditional with Guard Clauses
  75. Replace Parameter with Explicit Methods
  76. Replace Parameter with Method
  77. Replace Record with Data Class
  78. Replace Recursion with Iteration by Ivan Mitrovic
  79. Replace Static Variable with Parameter by Marian Vittek
  80. Replace Subclass with Fields
  81. Replace Temp with Query
  82. Replace Type Code with Class
  83. Replace Type Code with State/Strategy
  84. Replace Type Code with Subclasses
  85. Reverse Conditional by Bill Murphy and Martin Fowler
  86. Self Encapsulate Field
  87. Separate Data Access Code (Link Only)
  88. Separate Query from Modifier
  89. Split Loop by Martin Fowler
  90. Split Temporary Variable
  91. Substitute Algorithm
  92. Use a Connection Pool (Link Only)
  93. Wrap entities with session (Link Only)

##参考资料

  • 追求代码质量: 监视圈复杂度
  • 循环复杂度
  • 圈复杂度
  • 代码质量-圈复杂度及其计算
  • Refactoring
原创粉丝点击