避免 C# 中的代码异味:最佳实践和示例

作者:微信公众号:【架构师老卢】
2-18 19:1
100

代码异味是代码中潜在问题的指标,这些问题可能会导致维护挑战、可读性降低和引入错误的可能性增加。作为 C# 开发人员,了解这些代码气味并采用最佳做法来编写干净、可维护且高效的代码至关重要。在本文中,我们将探讨 C# 中常见的代码异味,并提供示例以及避免它们的策略。

1.长方法:

长方法难以理解和维护。将冗长的方法分解为更小、更集中的方法,以提高可读性和可维护性。

// Code Smell  
public void ProcessData()  
{  
    // ... 100 lines of code ...  
}  
  
// Refactored  
public void ProcessData()  
{  
    ExtractMethod1();  
    ExtractMethod2();  
    // ...  
}  
  
private void ExtractMethod1()  
{  
    // ...  
}  
  
private void ExtractMethod2()  
{  
    // ...  
}

2. 大班:

大班通常是设计不佳的标志。考虑将大班级分解为更小的、有凝聚力的班级,这些班级遵守单一责任原则 (SRP)。

// Code Smell  
public class DataProcessor  
{  
    // ... lots of methods and fields ...  
}  
  
// Refactored  
public class DataProcessor  
{  
    private FileReader _fileReader;  
    private DataValidator _dataValidator;  
  
    public DataProcessor(FileReader fileReader, DataValidator dataValidator)  
    {  
        _fileReader = fileReader;  
        _dataValidator = dataValidator;  
    }  
  
    // Methods related to file reading  
    // ...  
  
    // Methods related to data validation  
    // ...  
}

3.命名不一致:

不一致的命名约定会使代码变得混乱。对变量、方法和类采用一致的命名样式。

// Code Smell  
public class processData  
{  
    public void manipulateData()  
    {  
        int a;  
        string b_c;  
    }  
}  
  
// Refactored  
public class DataProcessor  
{  
    public void ManipulateData()  
    {  
        int counter;  
        string dataString;  
    }  
}

4. 复杂条件语句:

复杂的条件语句会降低代码的可读性。简化条件并将它们提取到命名良好的方法中,以提高代码理解能力。

// Code Smell  
public void ProcessData(int value)  
{  
    if (value > 0 && value % 2 == 0 || value \< \-10)  
    {  
        // ...  
    }  
}  
  
// Refactored  
public void ProcessData(int value)  
{  
    if (IsValueValid(value))  
    {  
        // ...  
    }  
}  
  
private bool IsValueValid(int value)  
{  
    return (value > 0 && value % 2 == 0) || value < -10;  
}

5. 重复代码:

重复的代码会增加不一致的风险。创建可重用的方法或将通用功能提取到单独的类中。

// Code Smell  
public void ProcessDataA()  
{  
    // ... common code ...  
    // ... specific code for A ...  
}  
  
public void ProcessDataB()  
{  
    // ... common code ...  
    // ... specific code for B ...  
}  
  
// Refactored  
public void ProcessDataCommon()  
{  
    // ... common code ...  
}  
  
public void ProcessDataA()  
{  
    ProcessDataCommon();  
    // ... specific code for A ...  
}  
  
public void ProcessDataB()  
{  
    ProcessDataCommon();  
    // ... specific code for B ...  
}

6.评论过度使用:

过多的注释可能表明您的代码不言自明。通过对变量、方法和类使用清晰且有意义的名称来实现自记录代码。

// Code Smell  
public void ProcessData(int a, int b)  
{  
    // Add a to b  
    int result = a + b;  
    // Display the result  
    Console.WriteLine(result);  
}

7. 可变状态:

对对象状态的频繁更改可能会引入错误,并使代码更难推理。支持不可变性,并尽可能限制可变状态的使用。

// Code Smell  
public class MutablePerson  
{  
    public string Name { get; set; }  
    public int Age { get; set; }  
}  
  
// Refactored  
public class ImmutablePerson  
{  
    //private setters  
    public string Name { get; }  
    public int Age { get; }  
  
    public ImmutablePerson(string name, int age)  
    {  
        Name = name;  
        Age = age;  
    }  
}

8. 低效的字符串连接:

使用运算符重复连接字符串可能效率低下。用于获得更好的性能,尤其是在循环中。+StringBuilder

// Code Smell  
string result = "";  
for (int i = 0; i < 1000; i++)  
{  
    result += i.ToString();  
}  
  
// Refactored  
StringBuilder resultBuilder = new StringBuilder();  
for (int i = 0; i < 1000; i++)  
{  
    resultBuilder.Append(i);  
}  
string result = resultBuilder.ToString();

9. 缺乏错误处理:

忽略异常或未正常处理错误可能会导致不可预知的行为。始终在代码中包含适当的错误处理。

// Code Smell  
public int Divide(int a, int b)  
{  
    return a / b;  
}  
  
// Refactored  
public int Divide(int a, int b)  
{  
    if (b == 0)  
    {  
        // Handle division by zero  
        throw new ArgumentException("Cannot divide by zero.");  
    }  
    return a / b;  
}

10.紧密耦合:

高度耦合的代码在维护和修改方面可能具有挑战性。通过使用接口和依赖注入来实现松耦合。

// Code Smell  
public class OrderProcessor  
{  
    public void ProcessOrder()  
    {  
        PaymentProcessor paymentProcessor = new PaymentProcessor();  
        paymentProcessor.ProcessPayment();  
        // ...  
    }  
}  
  
// Refactored  
public class OrderProcessor  
{  
    private readonly IPaymentProcessor _paymentProcessor;  
  
    public OrderProcessor(IPaymentProcessor paymentProcessor)  
    {  
        _paymentProcessor = paymentProcessor;  
    }  
  
    public void ProcessOrder()  
    {  
        _paymentProcessor.ProcessPayment();  
        // ...  
    }  
}

11.功能嫉妒:

当一个方法似乎对另一个类的数据比它自己的数据更感兴趣时,就会发生特征嫉妒。这可能表明需要重构以改进封装。

// Code Smell  
public class ShoppingCart  
{  
    public decimal CalculateTotal(Order order)  
    {  
        // Feature envy, accessing properties of Order excessively  
        return order.Quantity * order.Price;  
    }  
}  
  
// Refactored  
public class Order  
{  
    public decimal CalculateTotal()  
    {  
        // Encapsulate the calculation within the Order class  
        return Quantity * Price;  
    }  
}

12. 数据块:

当一组变量或参数经常组合在一起时,就会发生数据团块。这可能表明这些变量属于一个通用的抽象。

// Code Smell  
public class OrderProcessor  
{  
    public void ProcessOrder(string orderId, DateTime orderDate, decimal amount)  
    {  
        // ...  
    }  
}  
  
// Refactored  
public class Order  
{  
    public string OrderId { get; set; }  
    public DateTime OrderDate { get; set; }  
    public decimal Amount { get; set; }  
}  
  
public class OrderProcessor  
{  
    public void ProcessOrder(Order order)  
    {  
        // ...  
    }  
}

13. 不恰当的亲密关系:

当班级紧密结合并可以访问彼此的内部细节时,就会发生不适当的亲密关系。这会使代码更加脆弱且更难维护。

// Code Smell  
public class Customer  
{  
    public string Name { get; set; }  
    public void SendInvoice(Invoice invoice)  
    {  
        // Customer knows too much about Invoice internals  
        invoice.Generate();  
    }  
}  
  
// Refactored  
public class Customer  
{  
    public string Name { get; set; }  
    public void SendInvoice(Invoice invoice)  
    {  
        // Customer interacts through a clean interface  
        invoice.Send();  
    }  
}  
  
public class Invoice  
{  
    public void Send()  
    {  
        // Implementation details for sending an invoice  
    }  
}

14. 懒惰类:

当类没有提供足够的值或功能来证明其存在时,就会发生惰性类。合并或消除此类类可能会更好。

// Code Smell  
public class UnusedClass  
{  
    // Minimal functionality or unused class  
}  
  
// Refactored  
// Merge the functionality of UnusedClass into another class or eliminate it if unnecessary

15. 霰弹枪手术:

当代码中的单个更改需要在多个位置进行修改时,就会发生 Shotgun 手术。这表明缺乏适当的封装。

// Code Smell  
public class Configuration  
{  
    public string DatabaseConnectionString { get; set; }  
    public string LogFilePath { get; set; }  
    // ... many other properties ...  
}  
  
// Refactored  
public class DatabaseConfiguration  
{  
    public string ConnectionString { get; set; }  
}  
  
public class LoggingConfiguration  
{  
    public string LogFilePath { get; set; }  
}  
  
// Usage  
var databaseConfig = new DatabaseConfiguration { ConnectionString = "..." };  
var loggingConfig = new LoggingConfiguration { LogFilePath = "..." };

16. 循环依赖:

当两个或多个类直接或间接相互依赖时,就会发生循环依赖关系。这可能会使代码更难理解和维护。

// Code Smell  
public class ClassA  
{  
    public void MethodA()  
    {  
        // Depends on ClassB  
    }  
}  
  
public class ClassB  
{  
    public void MethodB()  
    {  
        // Depends on ClassA  
    }  
}  


  
// Refactored  
// Introduce an interface or abstract class to break the cyclic dependency

通过解决这些代码异味,您可以为创建更干净、更易于维护和可读的代码做出贡献。定期的代码审查和对持续改进的承诺是避免和纠正 C# 项目中代码异味的基本做法。

相关留言评论
昵称:
邮箱:
阅读排行