超易懂!原来 SOLID 原则要这么理解!

article/2025/9/23 0:12:13

点击蓝色 “陈树义” 关注我哟

说到 SOLID 原则,相信有过几年工作经验的朋友都有个大概印象,但就是不知道它具体是什么。甚至有些工作了十几年的朋友,它们对 SOLID 原则的理解也停留在表面。今天我们就来聊聊 SOLID 原则以及它们之间的关系。

01 什么是 SOLID 原则

SOLID 原则其实是用来指导软件设计的,它一共分为五条设计原则,分别是:

  • 单一职责原则(SRP)

  • 开闭原则(OCP)

  • 里氏替换原则(LSP)

  • 接口隔离原则(ISP)

  • 依赖倒置原则(DIP)

单一职责原则(SRP)

单一职责原则(Single Responsibility Principle),它的定义是:应该有且仅有一个原因引起类的变更。简单地说:接口职责应该单一,不要承担过多的职责。 用生活中肯德基的例子来举例:负责前台收银的服务员,就不要去餐厅收盘子。负责餐厅收盘子的就不要去做汉堡。

单一职责适用于接口、类,同时也适用于方法。例如我们需要修改用户密码,有两种方式可以实现,一种是用「修改用户信息接口」实现修改密码,一种是新起一个接口来实现修改密码功能。在单一职责原则的指导下,一个方法只承担一个职能,所以我们应该新起一个接口来实现修改密码的功能。

单一职责原则的重点在于职责的划分,很多时候并不是一成不变的,需要根据实际情况而定。单一职责能够使得类复杂性降低、类之间职责清晰、代码可读性提高、更加容易维护。但它的缺点也很明显,就是对技术人员要求高,有些时候职责难以区分。

我们在设计一个类的时候,可以先从粗粒度的类开始设计,等到业务发展到一定规模,我们发现这个粗粒度的类方法和属性太多,且经常修改的时候,我们就可以对这个类进行重构了,将这个类拆分成粒度更细的类,这就是所谓的持续重构。

开闭原则(OCP)

开闭原则(Open Closed Principle),它的定义是:一个软件实体,如类、模块和函数应该对扩展开放,对修改关闭。简单地说:就是当别人要修改软件功能的时候,使得他不能修改我们原有代码,只能新增代码实现软件功能修改的目的。

这听着有点玄乎,我来举个例子吧。

这段代码模拟的是对于水果剥皮的处理程序。如果是苹果,那么是一种拨皮方法;如果是香蕉,则是另一种剥皮方法。如果以后还需要处理其他水果,那么就会在后面加上很多 if else 语句,最终会让整个方法变得又臭又长。如果恰好这个水果中的不同品种有不同的剥皮方法,那么这里面又会有很多层嵌套。

if(type == apple){//deal with apple 
} else if (type == banana){//deal with banana
} else if (type == ......){//......
}

可以看得出来,上面这样的代码并没有满足「对拓展开放,对修改封闭」的原则。每次需要新增一种水果,都可以直接在原来的代码上进行修改。久而久之,整个代码块就会变得又臭又长。

如果我们对剥水果皮这件事情做一个抽象,剥苹果皮是一个具体的实现,剥香蕉皮是一个具体的实现,那么写出的代码会是这样的:

public interface PeelOff {void peelOff();
}public class ApplePeelOff implement PeelOff{void peelOff(){//deal with apple}
}public class BananaPeelOff implement PeelOff{void peelOff(){//deal with banan}
}public class PeelOffFactory{private Map<String, PeelOff> map = new HashMap();private init(){//init all the Class that implements PeelOff interface }
}.....public static void main(){String type = "apple";PeelOff peelOff = PeelOffFactory.getPeelOff(type);  //get ApplePeelOff Class Instance.peelOff.pealOff();
}

上面这种实现方式使得别人无法修改我们的代码,为什么?

因为当需要对西瓜剥皮的时候,他会发现他只能新增一个类实现 PeelOff 接口,而无法在原来的代码上修改。这样就实现了「对拓展开放,对修改封闭」的原则。

里氏替换原则(LSP)

里氏替换原则(LSP)的定义是:所有引用基类的地方必须能透明地使用其子类的对象。简单地说:所有父类能出现的地方,子类就可以出现,并且替换了也不会出现任何错误。 例如下面 Parent 类出现的地方,可以替换成 Son 类,其中 Son 是 Parent 的子类。

Parent obj = new Son();
等价于
Son son  = new Son();

这样的例子在 Java 语言中是非常常见的,但其核心要点是:替换了也不会出现任何的错误。这就要求子类的所有相同方法,都必须遵循父类的约定,否则当父类替换为子类时就会出错。 这样说可能还是有点抽象,我举个例子。

public class Parent{// 定义只能扔出空指针异常public void hello throw NullPointerException(){}
}
public class Son extends Parent{public void hello throw NullPointerException(){// 子类实现时却扔出所有异常throw Exception;}
}

上面的代码中,父类对于 hello 方法的定义是只能扔出空指针异常,但子类覆盖父类的方法时,却扔出了其他异常,违背了父类的约定。那么当父类出现的地方,换成了子类,那么必然会出错。

其实这个例子举得不是很好,因为这个在编译层面可能就有错误。但表达的意思应该是到位了。

而这里的父类的约定,不仅仅指的是语法层面上的约定,还包括实现上的约定。有时候父类会在类注释、方法注释里做了相关约定的说明,当你要覆写父类的方法时,需要弄懂这些约定,否则可能会出现问题。例如子类违背父类声明要实现的功能。比如父类某个排序方法是从小到大来排序,你子类的方法竟然写成了从大到小来排序。

里氏替换原则 LSP 重点强调:对使用者来说,能够使用父类的地方,一定可以使用其子类,并且预期结果是一致的。

接口隔离原则(ISP)

接口隔离原则(Interface Segregation Principle)的定义是:类间的依赖关系应该建立在最小的接口上。简单地说:接口的内容一定要尽可能地小,能有多小就多小。

举个例子来说,我们经常会给别人提供服务,而服务调用方可能有很多个。很多时候我们会提供一个统一的接口给不同的调用方,但有些时候调用方 A 只使用 1、2、3 这三个方法,其他方法根本不用。调用方 B 只使用 4、5 两个方法,其他都不用。接口隔离原则的意思是,你应该把 1、2、3 抽离出来作为一个接口,4、5 抽离出来作为一个接口,这样接口之间就隔离开来了。

那么为什么要这么做呢?我想这是为了隔离变化吧! 想想看,如果我们把 1、2、3、4、5 放在一起,那么当我们修改了 A 调用方才用到 的 1 方法,此时虽然 B 调用方根本没用到 1 方法,但是调用方 B 也会有发生问题的风险。而如果我们把 1、2、3 和 4、5 隔离成两个接口了,我修改 1 方法,绝对不会影响到 4、5 方法。

除了改动导致的变化风险之外,其实还会有其他问题,例如:调用方 A 抱怨,为什么我只用 1、2、3 方法,你还要写上 4、5 方法,增加我的理解成本。调用方 B 同样会有这样的困惑。

在软件设计中,ISP 提倡不要将一个大而全的接口扔给使用者,而是将每个使用者关注的接口进行隔离。

依赖倒置原则(DIP)

依赖倒置原则(Dependence Inversion Principle)的定义是:高层模块不应该依赖底层模块,两者都应该依赖其抽象。抽象不应该依赖细节,即接口或抽象类不依赖于实现类。细节应该依赖抽象,即实现类不应该依赖于接口或抽象类。简单地说,就是说我们应该面向接口编程。通过抽象成接口,使各个类的实现彼此独立,实现类之间的松耦合。

如果我们每个人都能通过接口编程,那么我们只需要约定好接口定义,我们就可以很好地合作了。软件设计的 DIP 提倡使用者依赖一个抽象的服务接口,而不是去依赖一个具体的服务执行者,从依赖具体实现转向到依赖抽象接口,倒置过来。

02 SOLID 原则的本质

我们总算把 SOLID 原则中的五个原则说完了。但说了这么一通,好像是懂了,但是好像什么都没记住。 那么我们就来盘一盘他们之间的关系。ThoughtWorks 上有一篇文章说得挺不错,文中说:

  • 单一职责是所有设计原则的基础,开闭原则是设计的终极目标。

  • 里氏替换原则强调的是子类替换父类后程序运行时的正确性,它用来帮助实现开闭原则。

  • 而接口隔离原则用来帮助实现里氏替换原则,同时它也体现了单一职责。

  • 依赖倒置原则是过程式编程与面向对象编程的分水岭,同时它也被用来指导接口隔离原则。

图片 l 来自 ThoughtWorks

简单地说:依赖倒置原则告诉我们要面向接口编程。当我们面向接口编程之后,接口隔离原则和单一职责原则又告诉我们要注意职责的划分,不要什么东西都塞在一起。

当我们职责捋得差不多的时候,里氏替换原则告诉我们在使用继承的时候,要注意遵守父类的约定。而上面说的这四个原则,它们的最终目标都是为了实现开闭原则。

参考资料

  • 写了这么多年代码,你真的了解 SOLID 吗?- 知乎

  • 如何理解 SOLID 原则?- ThoughtWorks 洞见

  • 重构的七宗罪 - ThoughtWorks 洞见


推荐阅读

  • 为什么要学设计模式:本质、价值与收益

  • 架构师必读:日均 500 万数据,如何进行数据存储选型?

  • 效率工具:如何快速复制页面标题和链接?

  • 有赞 CTO 崔玉松:我想打造出中国最好的技术团队

  • 技术 Leader 一定要懂所有业务细节吗?

  • 消失的这一个月,我都做了些啥?

  • 做了两年技术 Leader,聊聊我的技术管理思考

  • 我双十一省了一个亿,聊聊我的购物消费观

  • 时间真的就像海绵里的水,挤挤就会有吗?


公众号 @陈树义,用最简单的语言,分享我的技术见解。


http://chatgpt.dhexx.cn/article/1jIeUOTN.shtml

相关文章

SOLID五大原则【图解】

目录 前序 五大基本原则-SOLID 1. SRP 2. OCP 3. LSP 4. ISP 5. DIP 参考链接 前序 做C语言开发的应该都知道&#xff0c;C是面向过程开发的&#xff0c;而c是面向对象开发的。而封装、继承与多态是面向对象开发的三大特征。 但你可能不知道OOD(Object-Oriented Desi…

我所理解的SOLID原则

S.O.L.I.D 是面向对象设计(OOD)和面向对象编程(OOP)中的几个重要编码原则(Programming Priciple)的首字母缩写。 面向对象设计的原则 SRP The Single Responsibility Principle单一职责原则OCP The Open Closed Principle开放封闭原则LSP The Liskov Substitution Principle里…

浅谈 SOLID 原则的具体使用

单一职责原则&#xff08;SRP&#xff09;开放封闭原则&#xff08;OCP&#xff09;里氏替换原则&#xff08;LSP&#xff09;接口隔离原则&#xff08;ISP&#xff09;依赖倒置原则&#xff08;DIP&#xff09;小结 SOLID 是面向对象设计5大重要原则的首字母缩写&#xff0c;当…

设计模式之SOLID原则再回首

本科阶段学过设计模式,那时对设计模式的五大原则——SOLID原则的概念与理解还是比较模糊,此时过去了2年时间,在学习《高级软件工程》课程中老师又提到了设计模式,课程中还详细讨论了五大原则的过程,这次SOLID原则再回首作者提出了一些更通俗的理解吧~ 一. 什么是设计模式&…

程序设计原则之SOLID原则

设计模式中的SOLID原则&#xff0c;分别是单一原则、开闭原则、里氏替换原则、接口隔离原则、依赖倒置原则。前辈们总结出来的&#xff0c;遵循五大原则可以使程序解决紧耦合&#xff0c;更加健壮。 SOLID原则是由5个设计原则组成&#xff0c;SOLID对应每个原则英文字母的开头…

SOLID原则

SOLID原则是一组设计原则&#xff0c;它们旨在帮助开发人员创建易于维护和可扩展的软件系统&#xff0c;这些原则的缩写代表以下5个原则&#xff1a; 1. 单一职责原则&#xff08;SRP&#xff09;&#xff1a;一个类应该只有一个职责。 2. 开闭原则&#xff08;OCP&#xff09;…

【KAFKA】kafka可视化工具kafkaTool 免费下载

【资源是免费的&#xff0c;官网可下载&#xff0c;可是官网下载的网络实在是太慢了有时候还会断线&#xff0c;我也是花了很长时间才下载下来的&#xff0c;提供给大家一个方便】 符合kafka version 0.11 mac 版&#xff1a;链接:https://pan.baidu.com/s/1q6qKrEbaDGukvqH…

windows 安装kafka流程

1、安装jdk 安装地址&#xff1a;www.oracle.com/java/technologies/downloads 下载好后进行安装&#xff0c;基本上一路点击下一步&#xff0c;不要忘记了把安装目录更换一下&#xff01; 安装好后需要配置环境变量 找到 "计算机-属性-高级系统设置-高级-环境变量“ 1&…

Window下安装Kafka

目录 一、下载安装 二、配置 三、启动 一、下载安装 注意&#xff1a;Kafka安装文件中包含zookeeper 首先打开Kafka的网站&#xff1a;https://kafka.apache.org/ 点击 Download Kafka&#xff0c;选择适合的版本进行下载。 这里后缀 .tgz 格式文件兼容Windows系统&#x…

kafka的安装和使用(详细版)

原创地址&#xff1a; https://www.cnblogs.com/lilixin/p/5775877.html Kafka安装与使用 下载地址&#xff1a;https://www.apache.org/dyn/closer.cgi?path/kafka/0.8.1.1/kafka_2.10-0.8.1.1.tgz 安装以及启动kafka 步骤1&#xff1a;安装kafka $ tar -xzf kafka_2.10-…

kafka-manager 的下载及安装

kafka-manager 的下载及安装 kafka-manager的功能 为了简化开发者和服务工程师维护Kafka集群的工作&#xff0c;yahoo构建了一个叫做Kafka管理器的基于Web工具&#xff0c;叫做 Kafka Manager。 这个管理工具可以很容易地发现分布在集群中的哪些topic分布不均匀&#xff0c;或…

怎样安装Kafka?

1、Kafka是Java开发的应用程序&#xff0c;可以运行在Windows、 MacOS和 Linux等多 种操作系统上。最常见的是将Kafka安装在Linux系统上。 2、在安装Kafka之前&#xff0c;需要先安装Java环境&#xff0c;虽然运行 Zookeeper 和 Kafka 只需要 Java运行时版本&#xff0c;但也可…

Kafka锦集(一):Kafka的介绍 | 下载和安装 | kafka服务无法关闭 | bin/kafka-server-stop.sh无效 | 总结的很详细

前言 从本篇开始&#xff0c;带你一起领略Kafka的世界&#xff0c;下面重点介绍它的下载、安装&#xff0c;带你避坑。 提示&#xff1a;如果你只是想解决“bin/kafka-server-stop.sh无效”的问题&#xff0c;直接下滑到文章尾部的4.2章节进行查看&#xff01; 一、Kafka介绍…

docker 下载kafka

Kafka采用的是订阅-发布的模式&#xff0c;消费者主动的去kafka集群拉取消息&#xff0c;与producer相同的是&#xff0c;消费者在拉取消息的时候也是找leader去拉取。 kafka存在的意义&#xff1a;去耦合、异步、中间件的消息系统 首先安装zookeeper docker search zookeepe…

windows下安装kafka

一.下载 kafka官网下载地址:http://kafka.apache.org/downloads.html,下载二进制的. 二.安装 1.安装zookeeper windows环境下安装zookeeper(单机版) 安装并启动后的界面: 2.安装kafka 我下载的kafka_2.13-2.8.0.tgz,并解压到D:\Tools\kafka_2.13-2.8.0目录下 编辑文件Kaf…

kafka tool下载安装和使用

一、下载安装 下载连接&#xff1a;https://www.kafkatool.com/download.html kafka tool官网介绍 Kafka工具是用于管理和使用Apache Kafka集群的GUI应用程序。 它提供了一种直观的UI&#xff0c;可让用户快速查看Kafka集群中的对象以及集群主题中存储的消息。 它包含面向开发…

[kafka] windows下安装kafka(含安装包)

[kafka] windows下安装kafka&#xff08;含安装包&#xff09; 目录 前言 一、下载kafka安装包 1&#xff09;下载安装包 2&#xff09;解压安装包 二、运行zookeeper 1.运行zookeeper&#xff08;因为kafka必须要和zookeeper一起运行&#xff09; 三、运行kafka 四、使用fafka…

1.Kafka下载安装

原文&#xff1a;kafka下载安装 一、安装jdk 参见&#xff1a;Linux环境下安装jdk1.8&#xff08;安装包版&#xff09; 二、安装kafka kafka安装包 链接&#xff1a;https://pan.baidu.com/s/1hy8XONH75fU-Djb_GBC-GA?pwdnmrs 提取码&#xff1a;nmrs1.解压kafka &…

Kafka在Linux下载安装及部署

前期准备工作&#xff1a; kafka的安装及使用需要用到ZooKeeper&#xff0c;所以需要提前安装搭建好ZooKeeper ZooKeeper在Linux下载安装及部署&#xff1a; Zookeeper在Linux下载安装及部署_学弟不想努力了-CSDN博客_zookeeper下载安装linuxhttps://blog.csdn.net/Eternal_Bl…

Kafka的常用命令(包括:下载安装、后台启动)

一、环境准备 首先JDK要在1.8及以上&#xff1b;然后安装对应版本的zookeeper。 本文以kafka2.7.2为例&#xff0c;关于如何找到kafka对应的zookeeper版本&#xff0c;参考我的这篇文章&#xff1a;如何确定kafka与zookeeper版本的对应关系。 1、安装Zookeeper3.5.9 Zookeep…