LOADING

加载过慢请开启缓存 浏览器默认开启

面向对象设计原则系列(1):七大原则总览


为什么需要设计原则?

  1. 降低耦合
    当类 A 直接依赖于类 B 的内部实现,任何对 B 的微小改动都可能引发 A 的连锁变更。通过设计原则,我们可以让各模块之间的依赖关系朝 抽象接口 方向转移,减少因实现细节改动带来的冲击面。

  2. 提高内聚
    将职责高度相关的逻辑聚拢到单个组件或类中,有利于定位问题和重构。当一个类只做一件事,且只做这一件事时,它就更容易理解、测试、扩展。

  3. 支持可扩展
    在满足 开闭原则 的情况下,我们可以新增功能(扩展)而不修改已有代码(闭合),最大程度避免回归缺陷。

  4. 增强可测试
    通过 依赖倒置接口隔离,可以轻松替换外部依赖为 Mock,在单元测试中只聚焦业务逻辑本身。


七大面向对象设计原则一览

序号 原则 英文缩写 核心关注
1 单一职责原则 SRP 责任分离:每个类/模块只承担一种原因引起的变化,通过高内聚降低噪声
2 开闭原则 OCP 可扩展性:用抽象(接口/基类)和多态,实现新增行为无需修改已有代码
3 里氏替换原则 LSP 行为契约:子类型在语义、前置/后置条件和不变式上必须与父类型保持兼容
4 接口隔离原则 ISP 细粒度接口:为不同客户角色定制最小功能集,避免“胖接口”与无用依赖
5 依赖倒置原则 DIP 依赖抽象:高层模块与底层模块都依赖于抽象,以接口为壁,减少实现耦合
6 组合复用原则 CRP 组合优先:通过对象组合/委托实现功能复用,替代脆弱的类继承层级
7 最少知识原则 LKP 最少暴露:对象只与直接朋友通信,限制链式依赖,降低模块间耦合

七大原则的相互关系

  • SRP → OCP → LSP → ISP → DIP 构成 SOLID 五原则,是保持类层面良好设计的“连环锁”。

  • CRP(Composite Reuse Principle)与 LKP(Least Knowledge Principle)补齐了 SOLID 在继承与对象交互方面的短板。

  • DIP 是 SOLID 中的“核心”,它保证了上层模块不会因下层模块变化而受到影响;而 LKP 则进一步约束了模块间的通信边界。

    flowchart LR
        SRP["单一职责 (SRP)"]
        OCP["开闭原则 (OCP)"]
        LSP["里氏替换 (LSP)"]
        ISP["接口隔离 (ISP)"]
        DIP["依赖倒置 (DIP)"]
        CRP["组合复用 (CRP)"]
        LoD["最少知识 (LKP)"]
    
        SRP --> OCP
        OCP --> LSP
        LSP --> ISP
        ISP --> DIP
        DIP --> CRP
        DIP --> LKP
        CRP --> LKP
    

简单示例:如何违反 SRP 与 DIP

// 反例:LogAndSaveOrder 既负责订单校验,又负责日志记录和持久化
public class OrderProcessor {
    public void Process(Order o) {
        if (!Validate(o)) throw new Exception("Invalid");
        Log($"Processing {o.Id}");
        SaveToDatabase(o);
    }
    // … Validate, Log, SaveToDatabase 均在同一类中
}

// 改进:单一职责 + 依赖倒置
public interface ILogger { void Log(string msg); }
public interface IOrderRepository { void Save(Order o); }

public class OrderProcessor {
    private readonly ILogger _logger;
    private readonly IOrderRepository _repo;
    public OrderProcessor(ILogger logger, IOrderRepository repo) {
        _logger = logger; _repo = repo;
    }
    public void Process(Order o) {
        if (!Validate(o)) throw new Exception("Invalid");
        _logger.Log($"Processing {o.Id}");
        _repo.Save(o);
    }
    bool Validate(Order o) { … }
}

SRP:OrderProcessor 只负责“流程控制”职责,ILogger 和 IOrderRepository 分别负责日志和持久化。

DIP:高层 OrderProcessor 依赖抽象 ILogger、IOrderRepository,无需关心具体实现。