作为一个喜欢遵循最佳实践的人,
如果我运行代码指标(右键单击解决方案资源管理器中的项目名称并选择“计算代码指标” - Visual Studio 2010):
public static string GetFormFactor(int number)
{
string formFactor = string.Empty;
switch (number)
{
case 1:
formFactor = "Other";
break;
case 2:
formFactor = "SIP";
break;
case 3:
formFactor = "DIP";
break;
case 4:
formFactor = "ZIP";
break;
case 5:
formFactor = "SOJ";
break;
}
return formFactor;
}
它给我一个 61 的可维护性指数
(当然,如果你只有这个,那么这是微不足道的,但是如果你使用像哲学这样的类这样的实用程序,那么你的实用程序类将具有最差的可维护性指数..)
这是解决方案吗?
答案 0 :(得分:26)
首先:61被认为是可维护的代码。对于可维护性指数,100很容易维护代码,而0很难维护。
可维护性指数基于三个代码指标:即Halstead Volumen,Cyclomatic Complexity和Code of Code并基于following formula:
MAX(0,(171 - 5.2 * ln)(Halstead 体积) - 0.23 *(Cyclomatic 复杂性) - 16.2 * ln(线条) 代码))* 100/171)
事实上,在您的示例中,可维护性指数的低值的根本原因是Cyclomatic Complexity。此度量标准是根据代码中的各种执行路径计算的。不幸的是,度量标准不一定与代码的“人类可读性”一致。
示例,因为您的代码导致索引值非常低(记住,lower越难维护)但实际上它们非常容易阅读。这在使用Cyclomatic Complexity来评估代码时很常见。
想象一下,代码有几天的开关块(Mon-Sun)加上几个月的切换块(Jan-Dec)。此代码将具有可读性和可维护性,但会导致巨大的Cyclomatic Complexity,因此Visual Studio 2010中的维护性指数非常低。
这是关于度量的众所周知的事实,如果根据数字判断代码,则应该考虑这个事实。不应查看绝对数字,而应随时监控这些数字,以便将其理解为代码更改的指标。例如。如果可维护性指数始终为100且突然降至10,则应检查导致此问题的变化。
答案 1 :(得分:5)
可维护性指数可能更高,因为您为解决方案选择的方法缺乏可扩展性。
正确的解决方案(上面提到的Mark Simpson)是可以扩展为使用新形状因子而不重建代码的解决方案 - 代码中的switch / case语句始终是OO设计已被遗忘的标志,应该总是被视为一种糟糕的代码味道。
就个人而言,我会实施......
interface IFormFactor
{
// some methods
}
class SipFormFactor : IFormFactor...
class DipFormFactor : IFormFactor...
Etc.
...并让界面上的方法提供所需的功能 - 您可以将其视为[我猜]与GoF命令模式类似。
这样你的高级方法就可以......
MyMethod(IFormFactor factor)
{
// some logic...
factor.DoSomething();
// some more logic...
}
...您可以在以后进行并引入新的外形,而不必像使用硬编码的switch子句那样更改此代码。您还会发现这种方法也很容易适用于TDD(如果您正在正确地进行TDD,您最终应该这样做),因为它很容易进行模拟。
答案 2 :(得分:3)
我知道这个答案很晚,但我感兴趣的是还没有人提出字典解决方案。我发现在处理像这样面向数据的巨大switch语句时,将switch-case折叠成字典通常更具可读性。
public static readonly IDictionary<int, string> Factors = new Dictionary<int, string> {
{ 1, "Other" },
{ 2, "SIP" },
{ 3, "DIP" },
{ 4, "ZIP" },
{ 5, "SOJ" }
};
public static string GetFormFactor2(int number)
{
string formFactor = string.Empty;
if (Factors.ContainsKey(number)) formFactor = Factors[number];
return formFactor;
}
这给你一个74的维护性指数 - 比数组解决方案略低,因为类耦合到字典,但我觉得它更通用,因为它适用于你通常会打开的任意数量的类型。与数组解决方案一样,它可以很好地扩展并删除大量重复代码。
一般来说,使用数据驱动的方法可以帮助您的代码更清晰,因为它将重要的部分(在这种情况下,条件和结果)与cruft(在这种情况下,switch-case)分开
答案 3 :(得分:2)
有两件事让人想起:
使用枚举结合描述和值
public enum FormFactor
{
Other = 1,
SIP = 2,
etc.
}
使用类或结构来表示每个外形
public class FormFactor
{
public int Index { get; private set; }
public string Description { get; private set; }
public FormFactor(int index, string description)
{
// do validation and assign properties
}
}
答案 4 :(得分:2)
我这样做,忘记了可维护性指数:
public static string GetFormFactor(int number)
{
switch (number)
{
case 1: return "Other";
case 2: return "SIP";
case 3: return "DIP";
case 4: return "ZIP";
case 5: return "SOJ";
}
return number.ToString();
}
恕我直言,易于阅读,易于更改。
答案 5 :(得分:0)
我不知道它有多重要,但以下是76:
private static string[] _formFactors = new[] { null, "Other","SIP","DIP", "ZIP", "SOJ"};
public static string GetFormFactor2(int number)
{
if (number < 1 || number > _formFactors.Length)
{
throw new ArgumentOutOfRangeException("number");
}
return _formFactors[number];
}
答案 6 :(得分:0)
显然对我来说, Enum 方法是最易维护的,因为它不涉及硬编码字符串,因此没有拼写错误问题和编译时语法检查。 只有限制是命名规则。