设计模式五大基本原则

设计模式中的五大基本原则,也称为SOLID原则,是面向对象设计的核心原则,它们帮助开发人员构建可扩展、可维护的系统。SOLID原则由罗伯特·C·马丁(Robert C. Martin)总结,这些原则的名称来自每个原则的首字母。它们分别是:

  1. 单一职责原则(Single Responsibility Principle,SRP)
  2. 开闭原则(Open/Closed Principle,OCP)
  3. 里氏替换原则(Liskov Substitution Principle,LSP)
  4. 接口隔离原则(Interface Segregation Principle,ISP)
  5. 依赖倒置原则(Dependency Inversion Principle,DIP)

1. 单一职责原则(SRP)

定义:一个类应该只有一个导致它变化的原因。

解释:每个类只应负责一项职责,或者说,一个类只应该有一个引起它变化的原因。职责越多,类的修改可能性越大,容易产生耦合问题。

例子

假设有一个 Employee 类负责员工信息存储和工资计算。如果未来业务需求变化,只需要修改工资计算的部分,但由于该类还包含其他职责,可能会无意中引入错误。

解决方案

Employee 类拆分为两个类,一个负责员工信息管理,一个负责工资计算。

kotlin 复制代码
class Employee {
    private String name;
    // 仅负责员工信息管理
}

class SalaryCalculator {
    // 负责工资计算
}

2. 开闭原则(OCP)

定义:软件实体应该对扩展开放,对修改关闭。

解释 :开闭原则的核心是通过扩展 而不是修改已有代码来应对需求的变化。换句话说,当我们需要新增功能时,应该通过新增代码(如新的类或模块),而不是修改已有代码。

例子

假设你有一个图形绘制系统,最初只能绘制圆形,现在需要扩展为绘制矩形。如果你直接修改原有代码,可能会引发新的问题。

解决方案

通过抽象类或接口来实现开闭原则,避免修改已有的绘图逻辑。

csharp 复制代码
interface Shape {
    void draw();
}

class Circle implements Shape {
    public void draw() {
        // 绘制圆形
    }
}

class Rectangle implements Shape {
    public void draw() {
        // 绘制矩形
    }
}

3. 里氏替换原则(LSP)

定义:派生类必须能够替换其基类,而不影响程序的正确性。

解释:子类可以替换父类并且保证程序行为不变。如果在使用基类的地方不能透明地替换为子类,那就违反了里氏替换原则。

例子

假设你有一个父类 Bird,它包含一个 fly 方法。然后你创建了一个子类 Penguin,但企鹅不能飞。如果你把企鹅放入需要飞行的地方,系统行为就会异常,违反了里氏替换原则。

解决方案

使用更具体的抽象,比如创建 FlyingBird 类,而不是让所有鸟类都继承 fly 方法。

scala 复制代码
class Bird {
    // 一般鸟类的属性和方法
}

class FlyingBird extends Bird {
    void fly() {
        // 具有飞行能力的鸟类
    }
}

class Penguin extends Bird {
    // 企鹅不具有飞行能力
}

4. 接口隔离原则(ISP)

定义:不应该强迫一个类实现它用不到的接口。

解释:与其让类实现一个庞大的接口,不如将接口拆分为多个更小、更具体的接口。这样,类只需要依赖它实际需要的接口方法。

例子

假设有一个 Worker 接口,包含 work()eat() 方法。如果一个机器人类需要实现 Worker 接口,它可能不需要 eat() 方法。

解决方案

将接口分解为更小的接口,让类按需实现它们。

csharp 复制代码
interface Workable {
    void work();
}

interface Eatable {
    void eat();
}

class Robot implements Workable {
    public void work() {
        // 机器人工作
    }
}

class Human implements Workable, Eatable {
    public void work() {
        // 人类工作
    }
    
    public void eat() {
        // 人类进食
    }
}

5. 依赖倒置原则(DIP)

定义:高层模块不应该依赖低层模块,二者都应该依赖其抽象。抽象不应该依赖细节,细节应该依赖抽象。

解释:这个原则的重点是通过依赖抽象(接口或抽象类)来降低耦合度,而不是直接依赖具体实现。依赖倒置使系统更具灵活性和扩展性。

例子

假设你有一个 Button 类,它直接依赖于 Light 类来打开灯,这样会导致高层模块(Button)依赖于低层模块(Light)。

解决方案

通过依赖抽象,来降低类之间的耦合度。

csharp 复制代码
interface Switchable {
    void turnOn();
}

class Light implements Switchable {
    public void turnOn() {
        System.out.println("Light turned on");
    }
}

class Button {
    private Switchable device;

    public Button(Switchable device) {
        this.device = device;
    }

    public void press() {
        device.turnOn();
    }
}

通过依赖接口 SwitchableButton 类不再直接依赖 Light 类。这样,Button 可以用来控制任何实现了 Switchable 接口的设备。


总结

  1. 单一职责原则:一个类应只有一个引起变化的原因。
  2. 开闭原则:类应对扩展开放,对修改关闭。
  3. 里氏替换原则:子类可以替代父类而不影响系统的行为。
  4. 接口隔离原则:应提供小而专一的接口,避免依赖多余的方法。
  5. 依赖倒置原则:高层模块应依赖抽象,细节模块也应依赖抽象。
相关推荐
To_OC1 小时前
别再串行写 await 了,Promise.all 才是并行请求的正确打开方式
前端·javascript·promise
vipbic1 小时前
中后台越做越乱后,我用插件化把它救回来了
前端·vue.js
Hyyy2 小时前
Computer Use 适合做什么,不适合做什么——一次真实使用后的思考
前端
小和尚同志2 小时前
前端 AI 单元测试思考与落地
前端·人工智能·aigc
invicinble3 小时前
c端系统,其实更像一个信息展示平台
前端
李姆斯4 小时前
管理是否可以被完全量化
前端·产品经理·团队管理
戮漠summer4 小时前
Missing Semester 计算机教育中缺失的一课 Lecture 01 Shell
开发语言·后端·scala
名字还没想好☜5 小时前
Next.js 中间件实战:鉴权、重定向与 A/B 分流
开发语言·前端·javascript·中间件·react·next.js
广州灵眸科技有限公司5 小时前
瑞芯微RV1126B开发板(EASY-EAI-PI2) INI文件操作
java·前端·javascript·网络·人工智能
江华森5 小时前
Web 开发基础:HTTP 与 REST
前端·网络协议·http