软件设计七大原则与设计模式本质
在面向对象软件开发中,我们追求的核心目标是:高内聚、低耦合。这能使我们的系统具有极佳的可重用性、可维护性与可扩展性。
软件设计原则是构建高质量代码的顶层思想,而设计模式则是为了达成这些原则而总结出的特定经典范式。本篇将系统总结软件设计七大原则(SOLID + 2)以及设计模式的分类本质。
1. 软件设计七大原则
我们将面向对象设计原则概括为 SOLID 体系,外加 迪米特法则 和 合成复用原则。
1.1 单一职责原则 (Single Responsibility Principle, SRP)
- 本质:一个类只负责一项职责。也就是说,引起类变化的原因只能有一个。
- 物理直觉:正如一把精密的瑞士军刀,虽然它有很多小工具,但每个工具(主刀、开罐器、剪刀)各司其职,各自的升级修改不会影响其他工具的运行。如果把所有功能全部浇筑在同一块铁片上,修改剪刀就会导致主刀变钝。
1.2 开闭原则 (Open-Closed Principle, OCP)
- 本质:对扩展开放,对修改关闭。当需求发生变化时,应通过增加新的代码(扩展)来适应变化,而不是去修改原有的已测试通过的代码。
- 实现手段:通过抽象和多态。基类定义好规范框架,新增子类去实现细节。
1.3 里氏替换原则 (Liskov Substitution Principle, LSP)
- 本质:子类必须能够替换掉它们的基类。也就是说,任何基类可以出现的地方,替换成子类后,程序的行为都不应当发生任何改变。
- 核心要求:子类不能随意破坏父类的约定和前置条件。如果子类重写了父类非虚函数或破坏了其业务逻辑约束,就违背了 LSP 原则。
1.4 接口隔离原则 (Interface Segregation Principle, ISP)
- 本质:客户端不应该依赖它不需要的接口。也就是说,一个类对另一个类的依赖应该建立在最小的接口上。
- 核心要求:接口要尽量细化,不要设计庞大而臃肿的“胖接口”。宁可提供多个精细的、专注特定功能的小接口,也不要提供一个通用的巨无霸接口。
1.5 依赖倒置原则 (Dependency Inversion Principle, DIP)
- 本质:高层模块不应该依赖低层模块,二者都应该依赖其抽象。抽象不应该依赖细节,细节应该依赖抽象。
- 核心要求:针对接口编程,不要针对实现编程。
- 物理直觉:电脑主板和内存条之间依靠标准的 DDR 接口协议 进行连接。主板(高层)不需要知道内存条(低层)是三星还是美光的,只要它们都遵循 DDR 规范即可插拔替换。
1.6 迪米特法则 (Law of Demeter, LoD / 最少知识原则)
- 本质:只与你直接的朋友交谈。一个对象应当对其他对象有尽可能少的了解,弱化不相关的类之间的网络依赖。
- 核心要求:降低类之间的耦合度。如果两个类不必直接通信,那么这两个类就不应当发生直接的相互作用。
1.7 合成复用原则 (Composite Reuse Principle, CRP)
- 本质:尽量使用合成/聚合(Composition/Aggregation),而不是继承(Inheritance)来达到复用的目的。
- 核心原因:继承属于“白箱复用”,子类会无条件暴露父类的内部细节,破坏封装性(高耦合)。而合成/聚合是“黑箱复用”,对象只通过外部暴露的接口协作,极大地降低了耦合度。
2. 设计模式的本质分类
设计模式是为了实现上述设计原则而演化出的 23 种经典套路。它们按目的可划分为三大类:
2.1 创建型模式 (Creational Patterns)
- 本质:如何优雅地创建对象。它将对象的创建过程和使用过程进行解耦,使用户不用关心对象是如何被实例化的。
- 代表模式:单例模式 (Singleton)、工厂方法 (Factory Method)、抽象工厂 (Abstract Factory)、建造者 (Builder)、原型 (Prototype)。
2.2 结构型模式 (Structural Patterns)
- 本质:如何组装对象。它关注类和对象的组合,通过继承、合成等方式把类和对象结合起来形成更大的结构。
- 代表模式:适配器 (Adapter)、桥接 (Bridge)、装饰器 (Decorator)、外观 (Facade)、享元 (Flyweight)、代理 (Proxy)。
2.3 行为型模式 (Behavioral Patterns)
- 本质 | 对象间如何分配职责与传递消息。它关注对象之间的通信、协作以及算法职责的划分。
- 代表模式:观察者 (Observer)、策略 (Strategy)、模板方法 (Template Method)、命令 (Command)、状态 (State)、职责链 (Chain of Responsibility)。