C#中的SOLID原则:高级应用与实践案例

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

引言:当SOLID不再是理论

大多数开发者对SOLID缩写的理解停留在“一个类应该只负责一件事”的层面。然而,在涉及依赖注入(Dependency Injection)、微服务和异步模式的真实C# (.NET) 项目中,盲目遵循这些原则会导致相反的效果——过度复杂化、接口膨胀以及封装性被破坏。

在本文中,我们将SOLID视为一种用于做出架构决策的工具,而非一套教条。您将学习如何在高级场景中正确应用这些原则:使用IoC容器、以组合代替继承、通过接口处理错误以及测试Saga。



1. 单一职责:DDD中的职责边界

单一职责原则(SRP)常被误解为“一个类一个功能”。实际上,它指的是变更的原因(reason to change)。在C#和领域驱动设计(Domain-Driven Design)的上下文中,这意味着一个类应该仅因一个原因而变更,该原因与单个参与者或业务规则相关。



高级反模式:“上帝实体”

考虑一个典型的.NET中违反SRP的例子——OrderEntity类,它同时管理订单状态、计算税费、发送电子邮件以及通过Entity Framework将数据保存到数据库。



// ❌ 违反SRPpublic class OrderEntity{    public int Id { get; set; }    public decimal Total { get; set; }    public string Email { get; set; }

public void CalculateTax() { /* 税费逻辑 */ } public void SendConfirmation() { /* 发送电子邮件 */ } public void SaveToDatabase() { /* EF Core SaveChanges */ }}

问题:业务税费规则的变更(例如,新法规)将导致这个还负责发送通知的类发生变更。这增加了回归风险。



解决方案:通过DI分离服务

// ✅ 通过服务实现SRPpublic class Order{    public int Id { get; set; }    public decimal Total { get; set; }    // 仅包含状态,无任何逻辑}

public class TaxCalculator : ITaxCalculator{ public decimal Calculate(Order order) { /* ... */ }}

public class EmailService : INotificationService{ public Task SendConfirmation(Order order) { /* ... */ }}

public class OrderRepository : IRepository<Order>{ public Task SaveAsync(Order order) { /* EF Core */ }}

现在每个类都只有一个变更原因。DI容器(Microsoft.Extensions.DependencyInjection)通过构造函数将它们连接起来。



2. 开闭原则:通过策略和装饰器进行扩展

开闭原则(OCP)指出:类应对扩展开放,对修改关闭。在.NET中,这不仅可以通过继承实现,还可以通过结合策略(Strategy)和装饰器(Decorator)模式的组合来实现。



高级案例:规则增长的验证

假设您有一个订单验证系统。初始版本只检查金额和地址。一个月后,新增了一条规则“不能订购超过限额的商品”。我们不应修改OrderValidator类,而是使用组合。



// ❌ 违反OCP——修改现有类public class OrderValidator{    public bool Validate(Order order)    {        if (order.Total < 0) return false;        if (string.IsNullOrEmpty(order.Address)) return false;        // 新规则——修改类        if (order.Total > 10000) return false;        return true;    }}


// ✅ 通过验证器组合实现OCPpublic interface IValidator<T>{    bool Validate(T entity);}

public class TotalValidator : IValidator<Order>{ public bool Validate(Order order) => order.Total > 0;}

pu

博客

书籍推荐