SOLID原则是五条提升代码可维护性的设计准则,包括单一职责(类只做一件事)、开闭(对扩展开放、对修改关闭)、依赖倒置(依赖抽象而非实现)、里氏替换(子类可安全替换父类)和接口隔离(接口应小而专)。
C# 中的 SOLID 原则是五条设计准则,不是语法规范,也不是编译器强制要求——但它直接决定你写的代码能不能轻松加功能、改 Bug、写单元测试,或者交到别人手上时不被骂。
它解决的是“类越写越大、改一处崩三处、新加个支付方式要动七个文件”这类真实痛点。下面说清楚每条怎么用、为什么这么用、以及新手最常踩的坑。
典型错误是把 Employee 类塞进工资计算、数据库保存、邮件发送、日志记录——改发邮件格式?得打开这个类,顺便 review 一遍数据库连接字符串有没有写错。
正确做法是拆:Employee 只存属性;SalaryCalculator 负责算钱;DatabaseRepository 管增删改;EmailService 发邮件。
CustomerName 和 CustomerEmail 各建一个类,就过了——它们天然属于同一语义边界当你需要支持微信支付,却不得不去改 PaymentProcessor.Process() 方法加 if (type == "WeChat") 分支,就已经违反 OCP。
核心解法是抽象+多态:IPaymentMethod 接口定义 Pay(),让 WeChatPayment、CreditCardPayment 各自实现,PaymentProcessor 只依赖接口,不关心具体类型。
常见反模式:OrderService 直接 new SqlOrderRepository(),导致单元测试只能连真实数据库,或者换 MongoDB 就得重写全部服务层。
正确姿势:定义 IOrderRepository 接口,OrderService 构造函数接收它;SqlOrderRepository 和 MongoOrderRepository 各自实现——谁创建、谁传入,交给 DI 容器或工厂。
IEmailSender,别用 ISmtpClient
LSP 的本质是“父类能跑通的逻辑,子类不能悄悄绕过”。比如 Rectangle 继承 Shape 没问题,但若 Square 继承 Rectangle 并在 SetWidth 里强制同步 Height,那调用方按矩形逻辑设宽高后,面积就错了——这就是 LSP 破坏。
ISP 针对的是“大而全”的接口:比如 IMachine 同时定义 Print()、Scan()、Fax(),结果打印机实现类得给 Scan() 抛 NotSupportedException。应该拆成 IPrinter、IScanner、IFaxMachine。

真正难的不是记住这五个字母,而是每次写 class 前,多问一句:“它以后会因为几种不同的原因被修改?”——这个问题的答案,比任何设计模式都管用。