“代码如诗,架构如歌。设计原则,便是那不走调的节拍。”
🎯 前言:什么是设计原则?
在软件开发的世界里,我们追求的是高内聚、低耦合、可维护、易扩展。而设计原则就是那一把衡量代码质量的“戒尺”,帮助我们写出健壮、优雅的代码。
今天我们就来聊聊——面向对象的七大设计原则,每一条我都会配上一个小例子,助你理解记忆。
🧱 一、单一职责原则(SRP)
✨ 定义:
一个类只负责一项职责。 “只做一件事,并做好它。”
🧩 举个栗子:
class Report {
public void generate() {
System.out.println("生成报表内容");
}
public void print() {
System.out.println("打印报表");
}
public void sendEmail() {
System.out.println("发送报表邮件");
}
}
🔴 问题: 这个类管得太多,内容生成、打印、发送全干了, “劳模成灾” 。
✅ 重构方式:
class ReportGenerator { void generate() {} }
class ReportPrinter { void print() {} }
class EmailSender { void send() {} }
一个类干一件事,代码更容易维护和测试。
🧱 二、开闭原则(OCP)
✨ 定义:
对扩展开放,对修改关闭。
系统在需求变化时,通过扩展新代码而非修改原有代码来实现变化。
🧩 举个栗子:
class Shape {
public void draw() {
// 画形状
}
}
class Painter {
public void paint(Shape s) {
s.draw();
}
}
新增一个新图形,只需添加新类,不用修改 Painter ——这就符合开闭原则。
🧱 三、里氏替换原则(LSP)
✨ 定义:
所有能使用父类的地方,都可以透明地替换为其子类,且不会出错。
🧩 举个栗子:
class Bird {
public void fly() {
System.out.println("我在飞");
}
}
class Ostrich extends Bird {
@Override
public void fly() {
throw new RuntimeException("我不会飞!");
}
}
🔴 鸵鸟不能飞,但继承了 Bird 却有 fly() 方法,替换时程序崩了。
✅ 重构:
interface Flyable {
void fly();
}
class Sparrow implements Flyable { public void fly() {} }
class Ostrich {} // 不实现 Flyable
🧱 四、依赖倒置原则(DIP)
✨ 定义:
高层模块不应该依赖底层模块,两者都应依赖抽象。
🧩 举个栗子:
class MySQLConnection {
public void connect() {}
}
class DataAccess {
private MySQLConnection db = new MySQLConnection();
public void query() {
db.connect();
// ...
}
}
🔴 DataAccess 强依赖具体类,换数据库得改源码。
✅ 改为依赖接口:
interface DBConnection {
void connect();
}
class MySQLConnection implements DBConnection {
public void connect() {}
}
class DataAccess {
private DBConnection db;
public DataAccess(DBConnection db) {
this.db = db;
}
}
🧱 五、接口隔离原则(ISP)
✨ 定义:
不要强迫客户端依赖它不需要的接口。小而专的接口比大而全的接口好。
🧩 举个栗子:
interface Animal {
void eat();
void fly();
void swim();
}
class Dog implements Animal {
public void eat() {}
public void fly() {} // ❌狗不会飞
public void swim() {}
}
🔴 明明狗不会飞,还得实现飞的接口。
✅ 改为接口拆分:
interface Eater { void eat(); }
interface Flyer { void fly(); }
interface Swimmer { void swim(); }
class Dog implements Eater, Swimmer {}
class Bird implements Eater, Flyer {}
🧱 六、迪米特法则(LoD)
✨ 定义:
只与直接朋友通信,不和陌生人说话。
🧩 举个栗子:
class Engine {
public void start() {
System.out.println("启动引擎");
}
}
class Car {
private Engine engine = new Engine();
public Engine getEngine() {
return engine;
}
}
class Driver {
public void drive(Car car) {
car.getEngine().start(); // ❌ 触及内部对象
}
}
✅ Driver 应只调用 Car 的方法:
class Car {
private Engine engine = new Engine();
public void start() {
engine.start();
}
}
class Driver {
public void drive(Car car) {
car.start(); // ✅ 好的抽象封装
}
}
🧱 七、合成复用原则(CRP)
✨ 定义:
优先使用对象组合而非继承来达到复用。
🧩 举个栗子:
class Human {
public void speak() {
System.out.println("说话");
}
}
class Teacher extends Human {
public void teach() {
System.out.println("教学");
}
}
🔴 Teacher 继承 Human,看似没毛病,但如果 Human 改了,Teacher 也受影响。
✅ 更推荐使用组合:
class Human {
public void speak() {}
}
class Teacher {
private Human human = new Human();
public void teach() {}
public void speak() {
human.speak();
}
}
📚 最后的总结表
| 原则 | 简称 | 核心思想 | 示例关键词 |
|---|---|---|---|
| 单一职责原则 | SRP | 一个类只干一件事 | 报表生成拆分 |
| 开闭原则 | OCP | 扩展开放,修改关闭 | 多图形画图 |
| 里氏替换原则 | LSP | 子类替代父类不出错 | 鸟 vs 鸵鸟 |
| 依赖倒置原则 | DIP | 高层依赖接口,不依赖实现 | 数据访问层接口化 |
| 接口隔离原则 | ISP | 接口应小而专 | 动物能力拆分 |
| 迪米特法则 | LoD | 只与直接朋友通信 | Car 封装 Engine |
| 合成复用原则 | CRP | 多用组合,少用继承 | Teacher 包含 Human |
🧘 彩蛋:写好代码的秘密是什么?
正是这七条不起眼的设计原则,构成了优雅代码的七根支柱,撑起了大型系统不倒的骨架。
它们不是约束,而是自由的方向盘。