概念
C# 中面向对象编程的 SOLID 原则
本文详细介绍了面向对象设计的五大SOLID原则,帮助开发者构建可维护且可扩展的软件。
SRP: Splitting a non-SRP class
代码示例
1// 不符合 SRP 2public class RegisterService 3{ 4 public void RegisterUser(string username) 5 { 6 if (username == "admin") 7 throw new InvalidOperationException(); 8 9 SqlConnection connection = new SqlConnection(); 10 connection.Open(); 11 SqlCommand command = new SqlCommand("INSERT INTO [...]");//Insert user into database. 12 13 SmtpClient client = new SmtpClient("smtp.myhost.com"); 14 client.Send(new MailMessage()); //Send a welcome email. 15 } 16}
代码示例
1public void RegisterUser(string username) 2{ 3 if (username == "admin") 4 throw new InvalidOperationException(); 5 6 _userRepository.Insert(...); 7 8 _emailService.Send(...); 9}
OCP: Modifying OldClass instead of extending
代码示例
1// 不符合 OCP 2public double Area(object[] shapes) 3{ 4 double area = 0; 5 foreach (var shape in shapes) 6 { 7 if (shape is Rectangle) 8 { 9 Rectangle rectangle = (Rectangle) shape; 10 area += rectangle.Width*rectangle.Height; 11 } 12 else 13 { 14 Circle circle = (Circle)shape; 15 area += circle.Radius * circle.Radius * Math.PI; 16 } 17 } 18 19 return area; 20} 21 22public class AreaCalculator 23{ 24 public double Area(Rectangle[] shapes) 25 { 26 double area = 0; 27 foreach (var shape in shapes) 28 { 29 area += shape.Width*shape.Height; 30 } 31 32 return area; 33 } 34}
代码示例
1public abstract class Shape 2{ 3 public abstract double Area(); 4} 5 6public class Rectangle : Shape 7{ 8 public double Width { get; set; } 9 public double Height { get; set; } 10 public override double Area() 11 { 12 return Width*Height; 13 } 14} 15 16public class Circle : Shape 17{ 18 public double Radius { get; set; } 19 public override double Area() 20 { 21 return Radius*Radius*Math.PI; 22 } 23} 24 25public double Area(Shape[] shapes) 26{ 27 double area = 0; 28 foreach (var shape in shapes) 29 { 30 area += shape.Area(); 31 } 32 33 return area; 34}
LSP: seamless substitution for the B class in existing code
代码示例
1namespace SOLID_PRINCIPLES.LSP 2{ 3 class Program 4 { 5 static void Main(string[] args) 6 { 7 Apple apple = new Orange(); 8 Debug.WriteLine(apple.GetColor()); 9 } 10 } 11 public class Apple 12 { 13 public virtual string GetColor() 14 { 15 return "Red"; 16 } 17 } 18 public class Orange : Apple 19 { 20 public override string GetColor() 21 { 22 return "Orange"; 23 } 24 } 25}
代码示例
1namespace SOLID_PRINCIPLES.LSP 2{ 3 class Program 4 { 5 static void Main(string[] args) 6 { 7 Fruit fruit = new Orange(); 8 Debug.WriteLine(fruit.GetColor()); 9 fruit = new Apple(); 10 Debug.WriteLine(fruit.GetColor()); 11 } 12 } 13 public abstract class Fruit 14 { 15 public abstract string GetColor(); 16 } 17 public class Apple : Fruit 18 { 19 public override string GetColor() 20 { 21 return "Red"; 22 } 23 } 24 public class Orange : Fruit 25 { 26 public override string GetColor() 27 { 28 return "Orange"; 29 } 30 } 31}
ISP: Only inherit applicable methods
代码示例
1// 不符合接口隔离原则 2 3 public interface IWorker 4 { 5 string ID { get; set; } 6 string Name { get; set; } 7 string Email { get; set; } 8 float MonthlySalary { get; set; } 9 float OtherBenefits { get; set; } 10 float HourlyRate { get; set; } 11 float HoursInMonth { get; set; } 12 float CalculateNetSalary(); 13 float CalculateWorkedSalary(); 14 } 15 16 public class FullTimeEmployee : IWorker 17 { 18 public string ID { get; set; } 19 public string Name { get; set; } 20 public string Email { get; set; } 21 public float MonthlySalary { get; set; } 22 public float OtherBenefits { get; set; } 23 public float HourlyRate { get; set; } 24 public float HoursInMonth { get; set; } 25 public float CalculateNetSalary() => MonthlySalary + OtherBenefits; 26 public float CalculateWorkedSalary() => throw new NotImplementedException(); 27 } 28 29 public class ContractEmployee : IWorker 30 { 31 public string ID { get; set; } 32 public string Name { get; set; } 33 public string Email { get; set; } 34 public float MonthlySalary { get; set; } 35 public float OtherBenefits { get; set; } 36 public float HourlyRate { get; set; } 37 public float HoursInMonth { get; set; } 38 public float CalculateNetSalary() => throw new NotImplementedException(); 39 public float CalculateWorkedSalary() => HourlyRate * HoursInMonth; 40 }
代码示例
1// 符合接口隔离原则 2 3 public interface IBaseWorker 4 { 5 string ID { get; set; } 6 string Name { get; set; } 7 string Email { get; set; } 8 9 10 } 11 12 public interface IFullTimeWorkerSalary : IBaseWorker 13 { 14 float MonthlySalary { get; set; } 15 float OtherBenefits { get; set; } 16 float CalculateNetSalary(); 17 } 18 19 public interface IContractWorkerSalary : IBaseWorker 20 { 21 float HourlyRate { get; set; } 22 float HoursInMonth { get; set; } 23 float CalculateWorkedSalary(); 24 } 25 26 public class FullTimeEmployeeFixed : IFullTimeWorkerSalary 27 { 28 public string ID { get; set; } 29 public string Name { get; set; } 30 public string Email { get; set; } 31 public float MonthlySalary { get; set; } 32 public float OtherBenefits { get; set; } 33 public float CalculateNetSalary() => MonthlySalary + OtherBenefits; 34 } 35 36 public class ContractEmployeeFixed : IContractWorkerSalary 37 { 38 public string ID { get; set; } 39 public string Name { get; set; } 40 public string Email { get; set; } 41 public float HourlyRate { get; set; } 42 public float HoursInMonth { get; set; } 43 public float CalculateWorkedSalary() => HourlyRate * HoursInMonth; 44 }
DIP: Changes to Objects A and B will not affect the other
代码示例
1public interface ICustomerDataAccess 2{ 3 string GetCustomerName(int id); 4}
代码示例
1public class CustomerDataAccess: ICustomerDataAccess 2{ 3 public CustomerDataAccess() { 4 } 5 6 public string GetCustomerName(int id) { 7 return "Dummy Customer Name"; 8 } 9}
代码示例
1public class DataAccessFactory 2{ 3 public static ICustomerDataAccess GetCustomerDataAccessObj() 4 { 5 return new CustomerDataAccess(); 6 } 7}
代码示例
1public class CustomerBusinessLogic 2{ 3 ICustomerDataAccess _custDataAccess; 4 5 public CustomerBusinessLogic() 6 { 7 _custDataAccess = DataAccessFactory.GetCustomerDataAccessObj(); 8 } 9 10 public string GetCustomerName(int id) 11 { 12 return _custDataAccess.GetCustomerName(id); 13 } 14}
代码示例
1public interface ICustomerDataAccess 2{ 3 string GetCustomerName(int id); 4} 5 6public class CustomerDataAccess: ICustomerDataAccess 7{ 8 public CustomerDataAccess() { 9 } 10 11 public string GetCustomerName(int id) { 12 return "Dummy Customer Name"; 13 } 14} 15 16public class DataAccessFactory 17{ 18 public static ICustomerDataAccess GetCustomerDataAccessObj() 19 { 20 return new CustomerDataAccess(); 21 } 22} 23 24public class CustomerBusinessLogic 25{ 26 ICustomerDataAccess _custDataAccess; 27 28 public CustomerBusinessLogic() 29 { 30 _custDataAccess = DataAccessFactory.GetCustomerDataAccessObj(); 31 } 32 33 public string GetCustomerName(int id) 34 { 35 return _custDataAccess.GetCustomerName(id); 36 } 37}
Visual chart of our data access program