《写给 Java 程序员的七大设计原则全解析:别让你的代码变成意大利面》🍝

405 阅读4分钟

“代码如诗,架构如歌。设计原则,便是那不走调的节拍。”


🎯 前言:什么是设计原则?

在软件开发的世界里,我们追求的是高内聚、低耦合、可维护、易扩展。而设计原则就是那一把衡量代码质量的“戒尺”,帮助我们写出健壮、优雅的代码。

今天我们就来聊聊——面向对象的七大设计原则,每一条我都会配上一个小例子,助你理解记忆。


🧱 一、单一职责原则(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

image.png


🧘 彩蛋:写好代码的秘密是什么?

正是这七条不起眼的设计原则,构成了优雅代码的七根支柱,撑起了大型系统不倒的骨架。

它们不是约束,而是自由的方向盘。