软件开发SOLID设计原则

article/2025/9/23 0:09:28

前言:SOLID设计原则,不管是软件系统还是代码的实现,遵循SOLID设计原则,都能够有效的提高系统的灵活和可靠性,应对代码实现的需求变化也能更好的扩展和维护。因此提出了五大原则——SOLID。   我是通过老师讲解以及老师分享的笔记,然后加上自己的理解把它整理成笔记形式,分享给各位小伙伴一起学习!,同时也提升自己,巩固知识!

 

文章目录:

  1. 单一职责原则(SRP)
  2. 开闭原则(OCP)
  3. 里氏替换原则(LSP)
  4. 接口隔离原则(ISP)
  5. 依赖倒置原则(DIP)

一、单一职责原则(SRP)

单一职责原则 (SRP)英文全称为 Single Responsibility Principle ,是最简单的原则,同样也是最难用好的原则之一,主要的原因是:‘单一职责原则的范围把控’;它的定义比较简单:‘对于一个类而言,应该仅有一个引起它变化的原因。引起了变化的原因就是表示了这个类的职责’;它可能是某个特定领域的功能,可能是某个需求的解决方案。这个原则表达的是不要让一个类承担过多的责任,一旦有了多个职责,那么它就越容易因为某个职责而被更改,这样的状态是不稳定的,不经意的修改很有可能影响到这个类的其他功能。因此,我们需要将不同的职责封装在不同的类中,即将不同的变化原因封装在不同的类中,不同类之间的变化互不影响。

简单理解就是: 一类或者模块应该有且只有一个变化的原因,而不应该有多个原因。

看下面的刀叉图会更好的理解:

先写一个违反单一原则的代码例子:

//我在这里定义一个鸡类抽象类public abstract class Chickents{//来个鸡叫public void cockcsrow(){System.out.println("我会鸡叫");}//来个鸭叫public void cockcsrow(){System.out.println("我会鸭叫");}}

看上上面代码,有没有发现问题,我上面备注的是,专门给鸡类定义一个抽象类,也就是我这个抽象类必须是和鸡相关的,里面的方法也是只能和鸡相关的,不能包含其他的;但是,我这个类下面还有一个方法和鸭有关;这就说明了,我这个类违反了单一职责原则 ;

正确的写法:

//定义一个鸡类的抽象类
public abstract class Chickens{public void cockscrow(){System.out.println("我会鸡叫");}}

一个类只有一个职责,(和一个原因被更改)

二、开闭原则(OCP)

开闭原则 (OCP) 英文全称为 Open-Closed Principle,基本定义是软件中的对象(类,模块,函数等)应该对于扩展是开放的,但是对于修改是封闭的。这里的对扩展开放表示添加新的代码,就可以让程序行为扩展来满足需求的变化;对修改封闭表示在扩展程序行为时不要修改已有的代码,进而避免影响原有的功能。要实现不改代码的情况下,仍要去改变系统行为的关键就是抽象和多态,通过接口或者抽象类定义系统的抽象层,再通过具体类来进行扩展。这样一来,无须对抽象层进行任何改动,只需要增加新的具体类来实现新的业务功能即可,达到开闭原则的要求。

简单理解就是:我买一只鸡拿在手上,我又想买多只鸡,这时候,手拿不下,我们应该买个麻袋,放到一起,提着麻袋,而不是简单的全拿在手上。

再简单点理解:

扩展开放:添加新的实现类是开放的
修改关闭:修改原有代码是关闭的

看下面图有助于理解:

下面我写个加减违反开闭原则的代码例子

  /**** * @param a* @param b* @param po* * * 这里完成了加和减* @return*/public Double Calculator(Double a ,Double b ,String po){//转换一下防止精度丢失BigDecimal s1 = new BigDecimal(String.valueOf(a));BigDecimal s2 = new BigDecimal(String.valueOf(b));if("+".equals(po)){return s1.add(s2).doubleValue() ;}else if("-".equals(po)){return s1.subtract(s2).doubleValue() ;}else {throw new RuntimeException("没有别的符号了");}};

通过上面的例子,加和减已经写完了,这个时候,老王跑过来说:我要加两个个乘除的功能,这个时候我们是不是又要在下面 else if ,那么问题来了,开闭原则 ‘对修改封闭 ,就是我们在原有的代码,不能修改,我们做了修改,那么就是违反了开闭原则,我们该如何解决呢?我们创建一个接口就好了,注意,这个接口只针对计算,如果这个计算接口,还写了和计算不相关的代码,也就违反了单一原则。单一原则开闭原则它们是同时存在的 ;

下面我写个不违反开闭原则的代码例子

1)定义一个针对计算的接口

/**** @Date(时间)2023-05-30* @Author 半杯可可** 计算器接口*/
public interface NewCalculator {//做加减乘除的方法public Double NewCal(Double number1,Double number2) ;}

这个接口,创建好了,我们在们在创建一个类(可以是加法类,可以是减法类...),实现这个接口

2)创建个类

  2.1、加法类,进行加法运算

package com.lx.impl;import com.lx.dom.NewCalculator;import java.math.BigDecimal;/**** @Date(时间)2023-05-30* @Author 半杯可可** 加法运算*/
public class ADDCalculator  implements NewCalculator {@Overridepublic Double NewCal(Double number1, Double number2) {//转换BigDecimal防止双精度丢失BigDecimal a = new BigDecimal(String.valueOf(number1)) ;BigDecimal b = new BigDecimal(String.valueOf(number2)) ;return a.add(b).doubleValue();}
}

2.2、减法类,进行加法运算

package com.lx.impl;import com.lx.dom.NewCalculator;import java.math.BigDecimal;/**** @Date(时间)2023-05-30* @Author 半杯可可** 减法运算*/
public class SubtractionCalculator implements NewCalculator {@Overridepublic Double NewCal(Double number1, Double number2) {//转换BigDecimal防止双精度丢失BigDecimal a = new BigDecimal(String.valueOf(number1)) ;BigDecimal b = new BigDecimal(String.valueOf(number2)) ;return a.subtract(b).doubleValue();}
}

一个计算接口,我们通过类实现接口,再实现它的方法,当我们想实现加法功能的时候,我们创建一个加法类实现这个接口,通过接口的方法再实现相应的功能,想实现一个减法功能的时候,我们创建一个减法类实现这个接口再通过接口方法实现相应功能;这时老王过来说:实现一个乘除的功能;我们再创建两个乘除类实现接口,再通过接口方法实现相应功能 ;

三、里式替换原则 (LSP)

里式替换原则 (LSP) 英文全称为 Liskov Substitution Principle,基本定义为:在不影响程序正确性的基础上,所有使用基类的地方都能使用其子类的对象来替换。这里提到的基类和子类说的就是具有继承关系的两类对象,当我们传递一个子类型对象时,需要保证程序不会改变任何原基类的行为和状态,程序能正常运作。

简单理解就是:任何基类可以出现的地方,子类一定可以出现

看下图有助于理解:

这里我写一段违反里式替换原则代码实例:

1)创建一个类,实现某接口,类实现了所有接口的方法

package com.lx.violate.impl;import com.lx.violate.TestInf;/**** @Date(时间)2023-05-30* @Author 半杯可可*/
public class TestIn implements TestInf {@Overridepublic String si1() {return null;}@Overridepublic String si2() {return null;}@Overridepublic String si3() {return null;}@Overridepublic String si3(name) {System.out.println(name+"你最帅");return null;}
}

通过上面的代码,我们可以看到,我们重载了一个si3()方法,问题来了,根据里式替换原则:‘尽量不要重载父类的方法,换句话就是子类可以扩展父类的功能,但不能改变父类原有的功能

所以,我们这里不应该有重载方法的出现,如果想要添加新功能,可以在父类扩展一个方法。

正确的写法代码例子

package com.lx.violate.impl;import com.lx.violate.TestInf;/**** @Date(时间)2023-05-30* @Author 半杯可可*/
public class TestIn implements TestInf {@Overridepublic String si1() {return null;}@Overridepublic String si2() {return null;}@Overridepublic String si3() {return null;}}

这里只演示了一种最简单的例子,还有很多例子,就不一一展示了!

四、接口隔离原则(ISP)

接口隔离原则 (ISP) 英文全称为 Interface Segregation Principle,基本定义:客户端不应该依赖那些它不需要的接口。客户端应该只依赖它实际使用的方法,因为如果一个接口具备了若干个方法,那就意味着它的实现类都要实现所有接口方法,从代码结构上就十分臃肿。

简单理解就是:类所要实现的接口应该分解成多个接口,然后根据你所需要的功能去实现,并且在使用到接口方法的地方,用对应的接口类型去声明这个方法!

再简单点理解:

将一个大的接口拆分成多个小接口,根据需求去实现相应功能的接口。

看图有助于理解:

写一个违反接口隔离原则的代码例子:

1)创建接口

package com.lx.dom;/**** @Date(时间)2023-05-30* @Author 半杯可可*/
public interface TestInf {public void si1() ;public void si2() ;public void si3() ;}

2)创建User1类实现接口

package com.lx.dom;/**** @Date(时间)2023-05-30* @Author 半杯可可*/
public class Users1 implements TestInf{@Overridepublic void si1() {}@Overridepublic void si2() {}@Overridepublic void si3() {}
}

3)创建User2类实现接口

package com.lx.dom;/**** @Date(时间)2023-05-30* @Author 家辉*/
public class Users2 implements TestInf{@Overridepublic void si1() {}@Overridepublic void si2() {}@Overridepublic void si3() {}
}

通过上面的代码,我们可以分析,我们只要有一个类要实现这个接口,我们就必须实现这个接口的所有方法,问题来了,如果我User2类只想实现这个接口的一个方法,这时候该怎么办呢?如果我这个User2类还要实现别的功能,该怎么办呢?在接口隔离原则不可能在这个接口中在扩展一个方法啊,如果扩展了,那么就违反了口隔离原则。

  • JDK8提供了默认方法,相当于在接口中可以有一个默认的空实现,我们可以创建默认方法

  • 当子类实现这个接口时,只需要按需实现即可,意思就是需要实现哪个

  • 在创建一个新的接口

接口隔离原则:‘类所要实现的接口应该分解成多个接口,然后根据你所需要的功能去实现,并且在使用到接口方法的地方,用对应的接口类型去声明这个方法

正确的接口隔离原则的代码例子:

 1、创建TestInf接口

package com.lx.dom;/**** @Date(时间)2023-05-30* @Author 半杯可可*/
public interface TestInf {/*** JDK8提供了默认方法,相当于在接口中可以有一个默认的空实现,* 当子类实现这个接口时,只需要按需实现即可,意思就是需要实现哪个* 方法就重写哪个方法*/default void methodA(){}default void methodB(){}default void methodC(){}}

 2、创建User2Inf接口

package com.lx.dom;/**** @Date(时间)2023-05-30* @Author 半杯可可*/
public interface User2Inf {public void ma() ;
}

3、创建User2类实现TestInf,User2Inf两个接口

package com.lx.dom;/**** @Date(时间)2023-05-30* @Author 半杯可可* * 在实现多一个User2Inf接口,针对User2类的接口*/
public class User2 implements TestInf,User2Inf{@Overridepublic void methodB() {TestInf.super.methodB();}@Overridepublic void ma() {System.out.println("你们最帅/美");}
}

基于接口隔离原则,我们需要做的就是减少定义大而全的接口,类所要实现的接口应该分解成多个接口,然后根据所需要的功能去实现,并且在使用到接口方法的地方,用对应的接口类型去声明,这样可以解除调用方与对象非相关方法的依赖关系

五、依赖倒置原则 (DIP)

依赖倒置原则 (DIP) 英文全称 Dependency Inversion Principle, DIP),基本定义是:

  • 高层模块不应该依赖低层模块,两者应该依赖抽象;

  • 抽象不应该依赖细节,细节应该依赖抽象。

这里的抽象就是接口和抽象类,而细节就是实现接口或继承抽象类而产生的类。如果高层模块依赖于低层模块,那么低层模块的改动很有可能影响到高层模块,从而导致高层模块被迫改动,这样一来让高层模块的重用变得非常困难。因此可以在高层模块构建一个稳定的抽象层,并且只依赖这个抽象层;而由底层模块完成抽象层的实现细节。这样一来,高层类都通过该抽象接口使用下一层,移除了高层对底层实现细节的依赖。

简单理解就是:高层、底层两个模块依赖抽象,抽象不依赖细节,细节则依赖抽象;

再简单点:不应该依赖于具体实现,而是依赖于抽象;

看图更好理解:

总结:

  • 单一职责原则(SRP)
    • 控制类的颗粒大小,减少不相关代码功能的耦合,让类更加健壮;
  • 开闭原则(OCP)
    • 有了开闭原则,面向需求的各种变化能够进行快速的调整实现功能,提高了系统的灵活性、维护性、重用性;缺点就是会增加一定的‘复杂性’;
  • 里氏替换原则(LSP)
    • 里氏替换原则目的就是要保证继承关系的正确性,所有子类的行为功能必须和使用者对其父类的期望保持一致,如果子类达不到这一点,那么必然违反里氏替换原则 ;
  • 接口隔离原则(ISP)
    • 接口隔离原则主要功能就是控制接口的粒度大小,防止暴露给客户端无相关的代码和方法,保证了接口的高内聚,降低与客户端的耦合 ;
  • 依赖倒置原则(DIP)
    • 依赖倒置原则可以减少类间的耦合性,提高系统的稳定性,降低并行开发引起的风险,提高代码的可读性和可维护性 ;
    • 依赖倒置原则是框架设计的核心原则,善于创建可重用的框架和富有扩展性的代码 ;


http://chatgpt.dhexx.cn/article/lje0iVbU.shtml

相关文章

Python 中的 SOLID 原则

💂 个人网站:【海拥】【摸鱼游戏】【神级源码资源网】🤟 前端学习课程:👉【28个案例趣学前端】【400个JS面试题】💅 想寻找共同学习交流、摸鱼划水的小伙伴,请点击【摸鱼学习交流群】 SOLID 是一组面向对象…

Kotlin SOLID 原则

Kotlin SOLID 原则 许多 Kotlin 开发者并不完全了解 SOLID 原理,即使他们知道,他们也不知道为什么要使用它。您准备好了解所有细节了吗? 介绍 亲爱的 Kotlin 爱好者,您好!欢迎来到我的新文章。今天我要讲的是 Kotli…

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

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

SOLID五大原则【图解】

目录 前序 五大基本原则-SOLID 1. SRP 2. OCP 3. LSP 4. ISP 5. DIP 参考链接 前序 做C语言开发的应该都知道,C是面向过程开发的,而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 原则的具体使用

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

设计模式之SOLID原则再回首

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

程序设计原则之SOLID原则

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

SOLID原则

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

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

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

windows 安装kafka流程

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

Window下安装Kafka

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

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

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

kafka-manager 的下载及安装

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

怎样安装Kafka?

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

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

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

docker 下载kafka

Kafka采用的是订阅-发布的模式,消费者主动的去kafka集群拉取消息,与producer相同的是,消费者在拉取消息的时候也是找leader去拉取。 kafka存在的意义:去耦合、异步、中间件的消息系统 首先安装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下载安装和使用

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

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

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