问题描述
我目前正在为我的 c# 类做一个项目。我们的老师给了我们一些我们必须遵守的代码度量限制,其中之一是圈复杂度。现在他下面方法的复杂度是5,但它必须是4。有什么办法可以改进吗?
我正在谈论的方法:
private bool MethodName()
{
int counter = 0;
for (int k = 0; k < 8; k++)
{
for (int j = 0; j < 3; j++)
{
if (class1.GetBoard()[array1[k,j,0],array1[k,1]] == player.WhichPlayer()) counter++;
}
if (counter == 3) return true;
else counter = 0;
}
return false;
}
解决方法
我可以包装条件以减少它。例如
private bool MethodName()
{
for (int k = 0; k < 8; k++)
{
bool b = true;
for (int j = 0; j < 3; j++)
{
b &= class1.GetBoard()[array1[k,j,0],array1[k,1]] == player.WhichPlayer();
}
if (b) return true;
}
return false;
}
,
对于 OP(似乎刚刚开始编程):
很高兴你得到了一个降低方法圈复杂度的任务,知道它是什么以及如何将它保持在低水平作为一般做法是很好的。
但是,尽量不要对这些指标过于狂热。让代码尽可能简单更有价值,易于推理和快速理解,并且在分析应用程序并了解最重要的位置后才担心指标。
对于更有经验的编码人员:
这个简单的问题让我想起了 1968 年 very famous discussion 和 ACM 周期中的其他人之间的Dijkstra。虽然我倾向于在这件事上与他保持一致,但这是一个非常合理的answer from Frank Rubin。
弗兰克基本上主张“优雅”可以多次来自代码清晰度,而不是任何其他实践指标。当时的讨论是关于当时流行的语言过度使用 goto 语句。今天,讨论围绕圈复杂度、简洁性、oop 或其他内容展开。
我认为最重要的是:
- 了解您的工具
- 代码清晰
- 尝试在第一次通过时编写高效的代码,但不要想太多
- 分析您的代码并决定在何处花费更多时间
回到问题
问题中提出的实现在我的 Visual Studio Analyzer 中获得了以下分数:
循环。复合:5;可维护性:67
@Boris 提供的片段得到了这个:
循环。复合:4;可维护性:68
虽然圈复杂度有所提升,但可维护性指标基本保持不变。就我个人而言,我认为大多数情况下后一个指标更有价值。
只是为了好玩,让我们看看类似于 Frank Rubin 提出的使用可怕的 goto
语句的解决方案是什么样的:
private bool MethodName() {
for (int k = 0; k < 8; k++) {
for (int j = 0; j < 3; j++) {
if (watheverTestCondition(k,j) is false) goto reject;
}
// condition is true for all items in this row
return true;
// if condition is false for any item,go straight to this line
reject:;
}
return false;
}
老实说,我认为这是最清晰、最简单和最高效的实现。我一般推荐 goto
作为代码功能吗? 否。在这种特定情况下,它是否完美而顺利? 是的。那么指标呢?
循环。复合:4;可维护性:70
奖金
仅仅因为如果我不说我就睡不着,这就是你在现实生活中如何实现这一点:
obj.Any(row => row.All(watheverTestCondition));
循环。复合:1;可维护性:80