SOLID原则

article/2025/9/23 1:45:26

        SOLID原则是一组设计原则,它们旨在帮助开发人员创建易于维护和可扩展的软件系统,这些原则的缩写代表以下5个原则:

1. 单一职责原则(SRP):一个类应该只有一个职责。
2. 开闭原则(OCP):软件实体应该对扩展开放,对修改关闭。
3. 里式替换原则(LSP):子类应该能够替换其父类并保持系统行为的一致性。
4. 接口隔离原则(ISP):客户端不应该依赖于它不使用的接口。
5. 依赖反转原则(DIP):高层模块不应该依赖于底层模块,它们应该通过抽象接口进行交互。

        这些原则旨在提高软件系统的可维护性、可扩展性、可重用性和可测试性,使代码更加灵活、易于理解和修改。

SRP

        SRP(Single Responsibility Principle)是SOLID原则中的第一个原则,也是面向对象设计最重要的原则之一。它的原则是:一个类应该只有一个责任。

        简单地说,SRP要求将一个类的功能和职责限制在一个单独的领域内,避免一个类承担多个不相关的职责,而导致复杂、难以理解和维护的代码。

以下是SRP原则的几个关键点:

1. 每个类应该有一个明确的目的或职责,且该职责应该是单一的。

2. 一个类中应该只有一个引起它变化的原因。如果一个类有多个职责,那么这些职责会彼此耦合,导致一方面的改变会对另一方面产生影响,从而导致难以维护的代码。

3. SRP不是要求我们将每个类都写得非常小,而是要求我们遵循一种组织代码的原则,将代码组织得清晰和可读性高。

下面是一个违反SRP原则的示例:

public class Employee {public void calculatePay() {...}public void saveEmployee() {...}public void promoteEmployee() {...}
}

        上面的示例中,Employee类承担了三个职责:代表一个雇员、计算薪水、保存和推广员工。这违反了SRP原则,因为Employee类不应该承担那么多责任。

下面是一个遵循SRP原则的重构后的示例:

public class Employee {// responsibilities related to employee data managementpublic void saveEmployee() {...}// responsibilities related to employee promotionspublic void promoteEmployee() {...}// responsibilities related to employee salary calculationspublic void calculatePay() {...}
}public class EmployeeDao {public void saveEmployee(Employee employee) {...}
}public class EmployeeCalculator {public void calculatePay(Employee employee) {...}
}

        上面的示例中,我们将Employee类的职责分为三部分:维护员工数据、员工晋升和计算员工工资。三部分职责都被赋予了独立的类,每个类都可以专注于完成特定的职责,代码更易于维护和扩展。

OCP

        OCP(Open-Closed Principle)是SOLID原则中的第二个原则。它的原则是:软件实体(类、模块、函数等)应该对扩展开放(Open)而对修改关闭(Closed)。

        简单地说,OCP要求软件实体应该可以通过添加新的代码来扩展其行为,而不是通过修改现有的代码来改变其行为,从而避免导致其他模块或类出现问题。

以下是OCP原则的几个关键点:

1. 开放扩展,指的是允许在不修改可能会影响其他代码的情况下,添加新的功能和特性。

2. 关闭修改,指的是防止已有的代码被修改,而导致出现新的问题或引入新的错误。

3. 为了遵循OCP原则,可以使用抽象化方式,将变化预备在代码中。比如,定义一个接口,实现该接口的类都可以执行某种行为,新增功能时,则新建一个实现该接口的类即可。

下面是一个违反OCP原则的示例:

public class Car {private String make;private int model;private int year;public void startEngine() {...}public void stopEngine() {...}public void accelerate() {...}public void brake() {...}public void turnUpHeater() {...}
}

        上面的示例中,Car类有一段代码用于调节汽车加热器的温度,如果增加了新的功能,就会导致这个类发生变化,违反了OCP原则。

下面是一个遵循OCP原则的重构后的示例:

public interface Car {public void startEngine();public void stopEngine();public void accelerate();public void brake();
}public interface CarHeater {public void turnUpHeater();
} public class Ferrari implements Car {public void startEngine() {...}public void stopEngine() {...}public void accelerate() {...}public void brake() {...}
}public class Audi implements Car {public void startEngine() {...}public void stopEngine() {...}public void accelerate() {...}public void brake() {...}
}public class FerrariHeater implements CarHeater {public void turnUpHeater() {...}
}public class AudiHeater implements CarHeater {public void turnUpHeater() {...}
}

        上面的示例中,我们将CarHeater抽象成一个接口,定义了温度调节的行为,让不同的汽车都继承Car接口,对应实现自己的具体操作。这样,我们可以通过添加新的CarHeater实现类来增加新的功能,不需要修改Car类的代码,遵循了OCP原则。

LSP 

        LSP(Liskov Substitution Principle),即里氏替换原则,是SOLID原则中的第三个原则。它的原则是:任何使用父类引用的地方,都应该能够被其子类代替,且程序不会出错。

        简单来说,就是子类对象可以在任何需要父类对象的场合替代父类对象而不会影响程序的正确性。

        Java中的编译器强制规则(静态类型检查):

1.子类型可以增加方法,但不可删
2.子类型需要实现抽象类型 (接口、抽象类)中所有未实现的方法
3.子类型中重写的方法必须有相同或子类型的返回值或者符合co-variant的参数
4.子类型中重写的方法必须使用同样类型的参数或者符合contra-variant的参数(此种情况Java目前按照重载overload处理)
5.子类型中重写的方法不能抛出额外的异常

        也适用于指定的行为(方法):更强的不变量、更弱的前置条件、更强的后置条件

        LSP是一种子类型关系的特殊定义,称为强行为子类型化。

LSP原则举例:

class Car extends Vehicle {
int fuel;
boolean engineOn;
//@ invariant speed < limit;
//@ invariant fuel >= 0;
//@ requires fuel > 0 && !engineOn;
//@ ensures engineOn;
void start() { … }
void accelerate() { … }
//@ requires speed != 0;
//@ ensures speed < \old(speed)
void brake() { … }
}
class Hybrid extends Car {
int charge;
//@ invariant charge >= 0;
//@ requires (charge > 0 
|| fuel > 0) && !engineOn;
//@ ensures engineOn;
void start() { … }
void accelerate() { … }
//@ requires speed != 0;
//@ ensures speed < \old(speed)
//@ ensures charge > \old(charge)
void brake() { … }
}

        从代码一到代码二,子类满足相同的不变量(以及额外的不变量),start方法前置条件更弱,brake方法后置条件更强。

在编程语言中,LSP依赖于以下限制:

协变:

        父类型→子类型:越来越具体specific;返回值类型:不变或变得更具体;异常的类型:也是如此。

        数组是协变的,泛型不是协变的。(类型擦拭)

如何实现两个泛型类的协变?

        可采用通配符实现两个泛型类的协变。

无限定通配符?使用的两种情况:

情况1:方法的实现不依赖于类型参数(不调用其中的方法);

情况2:或者只依赖于Object 类中的功能

无限定通配符,一般用于定义一个引用变量,其可以指向多个不同类型的变量:

SuperClass<?> sup0 = new SuperClass<String>();
sup0 = new SuperClass<People>();
sup0 = new SuperClass<Animal>();

<? super A> 下限通配符              

 <? extends A> 上限通配符

public static double sumOfList(List<? extends Number> list) {
double s = 0.0;
for (Number n : list)
s += n.doubleValue();
return s;
}
List<Integer> li = Arrays.asList(1, 2, 3);
List<Double> ld = Arrays.asList(1.2, 2.3, 3.5);

注:List<? extends Number> list,意味着list可以匹配多种类型中的一种,但并不意味着同一个list可以存放所有的这些类型,无限定通配符和下限通配符同理。

        一个类型变量如果有多个限定(类或接口),则它是所有限定类型的子类型;如果多个限定中有类(至多只允许一个类),要写到声明的最前面。

Class A { /* ... */ }
interface B { /* ... */ }
interface C { /* ... */ }
class D <T extends A & B & C> { /* ... */ }

        限定的类型参数允许调用限定类型中的方法。

反协变(逆变):

        父类型→子类型:越来越具体specific

参数类型:要相反的变化,要不变或越来越抽象

注:目前Java中遇到参数逆变、参数协变都当作overload处理。

ISP

        ISP (Interface Segregation Principle) 接口隔离原则是 SOLID 原则中的第四个原则,它的基本思想是:将一个庞大的接口按照功能拆分成独立的小接口。

        具体来说,ISP原则要求我们在设计接口的时候,不应该尝试一次性把所有的功能都包含进一个接口,而是应该将其拆分成多个更小的接口,每个接口只包含与其相关的功能,这样我们在使用接口的时候,就不需要依赖或引用那些我们并不需要的方法。通过接口的拆分,不需要的方法将不再被实现,从而提高系统的内聚性和灵活性。

以下是 ISP 原则的几个关键点:

  • 接口的职责应该是单一的,即每个接口只负责一个特定的行为。
  • 接口中的方法应该是用户可用的,不关系对于某些调用方是否具有意义的方法应该在接口设计上避免。
  • 接口应该尽可能小,这并不意味着我们应该将所有的接口都设计得很小,而是尽量保证每个接口只包含必需的方法和属性。

DIP 

        DIP (Dependency Inversion Principle) 依赖倒置原则是 SOLID 原则中的第五个原则,它旨在提高软件系统的稳定性和可维护性。

        DIP 原则的基本思想是:高层模块不应该依赖于低层模块,它们应该都依赖于抽象;而抽象不应该依赖于具体实现,而是具体实现应该依赖于抽象。

        具体来说,DIP 原则要求我们在设计代码结构时,要尽量避免高层模块直接依赖于低层模块,而应该通过抽象接口或抽象类来建立依赖关系。这样,高层模块就不会直接依赖于单个或几个具体的低层模块,而是依赖于它们所实现的抽象层,从而降低了模块之间的耦合,提高了系统的灵活性和可维护性。

以下是 DIP 原则的几个关键点:

  • 高层模块和低层模块不应该直接依赖于具体的实现,而是应该依赖于抽象接口或抽象类。
  • 抽象不应该依赖于具体实现,而是具体实现应该依赖于抽象。
  • 细节应该依赖于抽象,而不是抽象依赖于细节。

http://chatgpt.dhexx.cn/article/7YNUHnsL.shtml

相关文章

【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…

Kafka在windows下下载、启动、测试详细教程

目录 下载地址 启动 启动zookeeper 启动kafka 队列操作 创建消息队列名 删除消息队列名 查看所有的队列 测试 生产测试 消费测试 下载地址 Apache KafkaApache Kafka: A Distributed Streaming Platform.https://kafka.apache.org/downloadswindows下kafka3.0版本的…

kafka 下载安装

文章目录 第一章 kafka概述一、定义二、消息队列1、传统消息队列2、消息队列的两种模式&#xff08;1&#xff09;点对点模式&#xff08;2&#xff09;发布/订阅模式 三、kafka基础架构 第二章 Kafka安装一、安装部署1、集群规划 二、集群部署1、下载地址&#xff08;1&#x…

kafka下载与安装教程

Kafka下载安装教程 1.定义2.特性3.使用场景4.1.下载jar包4.2.解压到指定的文件夹4.3.修改配置文件4.4.启动kafka内置的zookeeper4.5.启动kafka服务4.6.创建一个名为 test1 的tiopic的测试主体 kafka4.7.创建生产消息的生产者4.8.创建消息消费者接收消息 1.定义 Kafka传统定义&…

CSRF(跨站请求伪造)原理

什么是CSRF&#xff1f; &#xff08;Cross Site Request Forgery, 跨站域请求伪造&#xff09;是一种网络的攻击方式&#xff0c;它在 2007 年曾被列为互联网 20 大安全隐患之一,也被称为“One Click Attack”或者Session Riding&#xff0c;通常缩写为CSRF或者XSRF&#xff…

Spring Security跨站请求伪造(CSRF)

CSRF&#xff08;Cross Site Request Forgery&#xff09; 跨站点请求伪造。是攻击者欺骗用户的浏览器去访问一个自己曾经认证过的网站。由于浏览器曾经认证过&#xff0c;所以被访问的网站会认为是真正的用户操作而去运行。这利用了 web 中用户身份验证的一个漏洞&#xff1a…

解决Csrf跨站请求伪造

Csrf跨站请求伪造原理&#xff1a; 1. 用户C打开浏览器&#xff0c;访问受信任网站A&#xff0c;输入用户名和密码请求登录网站A&#xff1b;2.在用户信息通过验证后&#xff0c;网站A产生Cookie信息并返回给浏览器&#xff0c;此时用户登录网站A成功&#xff0c;可以正常发送请…