引言:为什么C#中需要SOLID原则?
每位C#开发者迟早都会遇到“脏代码”的问题:类做了太多事情,依赖关系难以阅读,以及无法在不冒破坏整个项目风险的情况下进行修改。SOLID是罗伯特·马丁提出的五个面向对象设计基本原则的首字母缩写。它们有助于在C# (.NET)中创建灵活、可维护且可测试的代码。
在本文中,我们将结合理论基础和C#实践示例,逐一剖析每个SOLID原则。您将学习如何在真实项目中应用它们,并避免常见错误。
1. 单一职责原则 (SRP)
理论
一个类应该只有一个引起它变化的原因。换句话说,每个类只负责程序功能的一部分。违反SRP会导致修改一个操作(例如,保存到数据库)影响到计算或显示逻辑。
C#实践
考虑一个典型的违反SRP的例子——一个类同时计算工资并将员工保存到数据库:
// ❌ 违反SRP:类做了太多事情public class Employee{ public string Name { get; set; } public decimal Salary { get; set; }
public decimal CalculateBonus() { return Salary * 0.1m; }
public void SaveToDatabase() { // 保存到数据库的逻辑 Console.WriteLine("员工已保存到数据库"); }}通过分离职责来改进:
// ✅ SRP:每个类负责自己的任务public class Employee{ public string Name { get; set; } public decimal Salary { get; set; }}
public class BonusCalculator{ public decimal Calculate(Employee employee) { return employee.Salary * 0.1m; }}
public class EmployeeRepository{ public void Save(Employee employee) { Console.WriteLine("员工已保存到数据库"); }}2. 开闭原则 (OCP)
理论
软件实体(类、模块、函数)应该对扩展开放,对修改关闭。这意味着您可以添加新功能,而无需修改现有代码。
C#实践
假设我们需要计算不同形状的面积。违反OCP的做法是使用if-else或switch来处理每种新形状:
// ❌ 违反OCP:添加新形状时需要修改代码public class AreaCalculator{ public double Calculate(object shape) { if (shape is Circle circle) return Math.PI * circle.Radius * circle.Radius; else if (shape is Rectangle rect) return rect.Width * rect.Height; // 添加Triangle时,需要再写一个if return 0; }}解决方案是使用抽象和多态:
// ✅ OCP:通过继承扩展,不修改现有代码public abstract class Shape{ public abstract double GetArea();}
public class Circle : Shape{ public double Radius { get; set; } public override double GetArea() => Math.PI * Radius * Radius;}
public class Rectangle : Shape{ public double Width { get; set; } public double Height { get; set; } public override double GetArea() => Width * Height;}
public class AreaCalculator{ public double Calculate(Shape shape) { return shape.GetArea(); // 适用于任何形状 }}3. 里氏替换原则 (LSP)
理论
基类的对象应该可以被其子类的对象替换,而不会破坏