设计模式五大基本原则

设计模式中的五大基本原则,也称为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. 依赖倒置原则:高层模块应依赖抽象,细节模块也应依赖抽象。
相关推荐
携欢8 分钟前
POrtSwigger靶场之CSRF where token validation depends on token being present通关秘籍
前端·csrf
weixin_446260859 分钟前
MudBlazor:轻松构建美观的Web应用程序!
前端
谜亚星13 分钟前
GSAP学习(五)
前端·动效
code_Bo16 分钟前
基于vxe-table进行二次封装
前端·javascript·vue.js
小时前端16 分钟前
现代Web认证体系深度解析:从JWT原理到SSO架构设计
前端·面试
前端一课1 小时前
公开分享一个AI番茄短故事模块技术方案(含代码)
前端
晴殇i1 小时前
为什么现代 JavaScript 代码规范开始建议禁止使用 else ?
前端·javascript·前端框架
源力祁老师1 小时前
OWL与VUE3 的高级组件通信全解析
前端·javascript·vue.js
花开月正圆1 小时前
遇见docker-compose
前端
护国神蛙1 小时前
自动翻译插件中的智能字符串切割方案
前端·javascript·babel