设计模式五大基本原则

设计模式中的五大基本原则,也称为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. 依赖倒置原则:高层模块应依赖抽象,细节模块也应依赖抽象。
相关推荐
iReachers6 分钟前
WebView2与Chrome内核的区别和使用场景详细介绍
前端·chrome·webview2
困顿小狗1 小时前
vue2 项目webpack 4升5
前端·webpack
sleeppingfrog1 小时前
vue3中自定义组件的双向绑定
前端·javascript·vue.js
Domain-zhuo2 小时前
uniapp 应用的生命周期、页面的生命周期、组件的生命周期
前端·javascript·vue.js·前端框架·uni-app·html·ecmascript
旅行中的伊蕾娜2 小时前
uniapp炫酷导航按钮及轮播指示器组件
前端·javascript·vue.js·微信小程序·uni-app
拾光师2 小时前
视频生成缩略图
后端
Liberty_yes2 小时前
uniapp navigateTo、redirectTo、reLaunch等页面路由跳转方法的区别
前端·uni-app
凡人的AI工具箱2 小时前
每天40分玩转Django:Django中间件
开发语言·数据库·后端·python·中间件·django
山山而川粤2 小时前
社区生活超市系统|Java|SSM|JSP|
java·开发语言·后端·学习·mysql
TWenYuan2 小时前
vue响应式数据-修改对象的属性值,视图不更新
前端·javascript·vue.js