软件设计原则(七大原则)
引言:为什么要遵循设计原则?
什么是软件设计原则?
是一组指导方针,旨在帮助我们避开不良的软件设计。这些原则由 Robert Martin 在《敏捷软件开发:原则、模式与实践》一书中系统整理。
不良设计的三个特征:
- 僵化:难以改动,一处修改波及整个系统。
- 脆弱:每次改动都会引发意想不到的问题。
- 死板:代码难以在其他应用中重用。
设计原则的作用:
- 为编写高质量代码提供准则。
- 是设计模式的基础。
- 各原则相互补充,共同指导我们构建高内聚、低耦合的系统。
七大设计原则详解
开放封闭原则(Open-Closed Principle, OCP)
定义:软件实体(类、模块、函数等)应该对扩展开放,对修改关闭。
核心思想:
- 对扩展开放:当需求变化时,可以通过添加新代码来扩展功能。
- 对修改关闭:已有的稳定代码不应被修改。
实现方法:通过抽象类或接口定义稳定架构,用实现类扩展细节。
案例:搜狗输入法皮肤系统
// 抽象皮肤
abstract class Skin {
public abstract void display();
}
// 具体皮肤实现
class DefaultSkin extends Skin {
@Override public void display() { System.out.println("默认皮肤"); }
}
class KeFengSkin extends Skin {
@Override public void display() { System.out.println("克峰皮肤"); }
}
// 输入法主体(依赖抽象)
class SougouInput {
private Skin skin;
public void setSkin(Skin skin) { this.skin = skin; }
public void display() { skin.display(); }
}
// 使用
public class Test {
public static void main(String[] args) {
SougouInput input = new SougouInput();
input.setSkin(new DefaultSkin()); // 可随时替换为 KeFengSkin
input.display();
}
}
意义:提高复用性和可维护性,是最重要的设计原则。
单一职责原则(Single Responsibility Principle, SRP)
定义:一个类应该有且仅有一个引起它变化的原因。
通俗解释:一个类只负责一项职责。
适用范围:类、接口、方法。
优点:
- 降低类的复杂度。
- 提高可读性、可维护性。
- 降低变更风险。
案例:DAO 类拆分
❌ 违反原则:XXXDao 同时处理 User 和 Order 表的操作。

✅ 符合原则:拆分为 UserDao 和 OrderDao,各司其职。

注意:只有逻辑足够简单时,才可在代码级别暂时放宽该原则。
接口隔离原则(Interface Segregation Principle, ISP)
定义:
- 客户端不应被迫依赖它不使用的方法。
- 类间的依赖应建立在最小的接口上。
核心:接口要尽量细化,避免臃肿。
优点:
- 提高系统灵活性和可维护性。
- 提高内聚性,降低耦合。
- 减少代码冗余。
案例:动物行为接口
❌ 臃肿接口:
//行为
interface behavior{
void Eating(); //进食
void cannon(); //跑
void fly(); //飞行
}
//鸟类
class bird implements behavior{
@Override
public void Eating() {}
@Override
public void cannon() {}
@Override
public void fly() {}
}
//狗类
class dog implements behavior{
@Override
public void Eating() {}
@Override
public void cannon() {}
@Override
public void fly() {}
}
✅ 隔离后:
//进食
interface eat{
void Eating(); //进食
}
//飞禽
interface Birds{
void fly(); //飞
}
//犬科
interface Canidae{
void cannon(); //跑
}
//鸟类
class bird implements eat,Birds{
@Override
public void Eating() {}
@Override
public void fly() {}
}
//狗类
class dog implements eat,Canidae{
@Override
public void Eating() {}
@Override
public void cannon() {}
}
与单一职责原则的区别:
- 相同点:都强调拆分,减少耦合。
- 不同点:SRP 关注职责,ISP 关注接口设计。
依赖倒置原则(Dependency Inversion Principle, DIP)
定义:
- 高层模块不应依赖低层模块,两者都应依赖抽象。
- 抽象不应依赖细节,细节应依赖抽象。
核心理念:面向接口编程,而非实现编程。
三种依赖注入方式:
-
接口传递
interface IMessage { void sendMessage(Producer producer); } interface Producer { void produce(); } -
构造方法传递
class Worker implements IMessage { private Producer producer; public Worker(Producer producer) { this.producer = producer; } } -
Setter 方法传递
class Worker implements IMessage { private Producer producer; public void setProducer(Producer producer) { this.producer = producer; } }
案例:消息收发系统
interface IMessage { void send(); }
class Worker {
public void receive(IMessage msg) { msg.send(); } // 依赖接口
}
class DingDing implements IMessage {
@Override public void send() { System.out.println("钉钉消息"); }
}
class WeChat implements IMessage {
@Override public void send() { System.out.println("微信消息"); }
}
注意:
- 低层模块尽量有抽象类或接口。
- 变量声明类型尽量使用抽象。
- 继承时遵循里氏替换原则。
里氏替换原则(Liskov Substitution Principle, LSP)
定义:所有引用基类的地方必须能透明地使用其子类对象。
通俗理解:子类可以扩展父类功能,但不要修改父类原有功能。
继承的双刃剑:
- 优点:代码复用、扩展性。
- 缺点:侵入性、降低灵活性、增加耦合。
案例:计算器功能扩展
// 基类
class Base {}
class Calculator extends Base {
public int add(int a, int b) { return a + b; }
public int sub(int a, int b) { return a - b; }
}
class SuperCalculator extends Base {
private Calculator calculator = new Calculator(); // 组合替代继承
public int mul(int a, int b) {
int sum = calculator.add(a, b);
return 100 - sum; // 新功能
}
}
注意事项:
- 子类可实现父类的抽象方法,但不要覆盖非抽象方法。
- 子类可添加新方法。
- LSP 是开闭原则的实现手段之一。
迪米特法则(Law of Demeter, LoD)
定义:又称最少知识原则。一个对象应对其他对象有最少的了解,只与直接朋友通信。
什么是“直接朋友”?
- 成员变量
- 方法参数
- 方法返回值
案例:学校打印员工信息
// 学院管理类
class CollegeManager {
public List<CollegeEmployee> getAllEmployees() { ... }
// 将打印职责内聚到自身
public void printEmployees() {
getAllEmployees().forEach(e -> System.out.println(e.getId()));
}
}
// 总部管理类
class SchoolManager {
public void printAllEmployees(CollegeManager cm) {
// 只与 CollegeManager 直接通信,不接触 CollegeEmployee
cm.printEmployees();
}
}
核心:降低类间耦合,被依赖者尽量封装内部逻辑,依赖者只依赖该依赖的对象。
合成复用原则(Composite/Aggregate Reuse Principle, CARP)
定义:尽量使用组合/聚合,而不是继承来达到复用目的。
三种复用方式:
- 继承(耦合度高)
- 组合(整体拥有部分,生命周期相同)
- 聚合(整体包含部分,生命周期独立)
- 依赖(方法参数形式)
案例:类 A 有两个方法,类 B 想复用
七大原则总结
| 原则 | 核心思想 | 目的 |
|---|---|---|
| 开闭原则 | 对扩展开放,对修改关闭 | 提高扩展性,保证稳定 |
| 里氏替换 | 子类不修改父类原有功能 | 规范继承的使用 |
| 依赖倒置 | 面向接口编程 | 降低模块间耦合 |
| 单一职责 | 一个类只负责一项职责 | 提高内聚性 |
| 接口隔离 | 接口最小化,避免臃肿 | 降低实现类的负担 |
| 迪米特法则 | 只与直接朋友通信 | 降低类间耦合 |
| 合成复用 | 优先使用组合而非继承 | 提高灵活性,降低耦合 |
核心思想提炼
- 封装变化:找出应用中可能变化的部分,独立出来。
- 面向接口:针对接口编程,而非实现。
- 松耦合:为交互对象之间的松散耦合而努力。
最终目标:构建高内聚、低耦合的软件系统,使其易于维护、扩展和复用。

浙公网安备 33010602011771号