程序设计原则之SOLID原则

article/2025/9/23 1:27:01

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

SOLID原则是由5个设计原则组成,SOLID对应每个原则英文字母的开头:

单一职责原则(Single Responsiblity Principle)
开闭原则(Open Close Principle)
里式替换原则(Liskov Substitution Principle)
接口隔离原则(Interface Segregation Principle)
依赖反转原则(Dependency Inversion Principle)
 

SRP单一责任原则
OCP开放封闭原则
LSP里氏替换原则
ISP接口隔离原则
DIP依赖倒置原则




单一责任原则

指的是一个类或者一个方法只做一件事。如果一个类承担的职责过多,就等于把这些职责耦合在一起,一个职责的变化就可能抑制或者削弱这个类完成其他职责的能力。例如餐厅服务员负责把订单给厨师去做,而不是服务员又要订单又要炒菜。

这里写图片描述

一个协议翻译类,在协议翻译的过程中如果出现了异常,则把异常写入文件日志中。粗略看来这个类没有问题,但是如果我们需要把日志写入数据库,那么我么就需要改变代码。按照单一职责原则,这个类的设计就没有达到要求,因为日志规范的修改,确需要修改协议翻译类。为此我们可以引入专门的日志类来解决这个问题。如果再遇到日志相关的需求变更,我们只需要修改日志类就好了。
 




开放封闭原则

对扩展开放,对修改关闭。意为一个类独立之后就不应该去修改它,而是以扩展的方式适应新需求。例如一开始做了普通计算器程序,突然添加新需求,要再做一个程序员计算器,这时不应该修改普通计算器内部,应该使用面向接口编程,组合实现扩展。

这里写图片描述

程序 AnimalCounter 负责统计动物的腿数,如果我们要增加一种新动物比如 Sheep,我们就需要给 AnimalCounter 的 countFeet 函数增加一个判断,判断数组中是不是有 Sheep 实例,这就是说当有新的需求来的时候,我们得修改 AnimalCounter 代码,而不是扩展它。

下面的代码可以解决这个问题。我们使用了一个接口,鸡类和狗类都继承了这个接口,在 AnimalCounter 中我们只要调用这个接口就可以知道动物有多少只脚了。无论是再有绵羊类或者是昆虫类,它们只要继承了这个接口,AnimalCounter 都可以计算出动物的总脚数。也就是我们通过扩展 IAnimal 接口就可以满足需求,而不用修改 AnimalCounter 类。

里氏替换原则

所有基类出现的地方都可以用派生类替换而不会程序产生错误。子类可以扩展父类的功能,但不能改变父类原有的功能。例如机动车必须有轮胎和发动机,子类宝马和奔驰不应该改写没轮胎或者没发动机。

这里写图片描述




 

我们定义了一个类叫 Bird,这个接口有四个方法,然后我们有一个天鹅类,一个鸡类。可以看到,Bird 的四个方法用 Swan 类来代替是没有问题的,但是用 Chicken 类来代替当调用到 fly 方法的时候就会抛出异常。这个就不符合 Liskov 原则,因为作为 Bird 类的子类的 Chicken 类没有做到替换父类 Bird 类而不影响程序运行。解决方法是拆分Bird类的功能,因为家禽是不会飞的。
 

接口隔离原则

类不应该依赖不需要的接口,知道越少越好。例如电话接口只约束接电话和挂电话,不需要让依赖者知道还有通讯录。

这里写图片描述

类不应该被强迫去依赖它用不到的方法。大的原则是很多小而精的接口,要好于一个大一统的接口。比如下面的 ICar 接口,我们不应该为了大一统把加油 (fuel) 和 (Charge) 充电都放在里面,因为烧汽油的汽车才需要加油,使用电池驱动的电动车才需要充电。如果子类继承了父类中用不到的方法,子类也会打破上面的 Liskov 原则,也不利于将来的重构和优化。
 

依赖倒置原则

依赖反转说了两点:

高层模块不应该依赖低层模块,双方应该依赖抽象。
抽象不应该依赖细节,而细节应该依赖抽象。
听起来很绕口,不过这个确实是面向对象编程里解决紧耦合问题最重要的原则之一。通常的解决方案就是大名鼎鼎的依赖注入!

指的是高级模块不应该依赖低级模块,而是依赖抽象。抽象不能依赖细节,细节要依赖抽象。比如类A内有类B对象,称为类A依赖类B,但是不应该这样做,而是选择类A去依赖抽象。例如垃圾收集器不管垃圾是什么类型,要是垃圾就行。

例子图

比如 物品交易,我有牛,你有羊, 以物换物,相互依赖, 如果改为统一用货币来交易,则彼此不依赖,而是都依赖于各自的物品抽象--货币。 

下面的代码的任务是打印一个指定路径的文件,打印完成后发出 email。这个代码就违反了依赖反转原则,所有的 new 语句处都表示高层模块需要知道低层模块的细节,比如 Program 类就需要如何生成 PrinterService 和 EMailService,PrinterService 和 EMailService 的功能也没有被抽象出来。这样程序的功能在需要重构、扩展或者替换时高层模块和低层模块都需要知道对方的细节。

public Program {public static void main(String[] args) {var filePath = args[0];var printerService = new PrinterService();printerService.print(filePath);var emailService = new EMailService();emailService.send("surfirst@example.com", "File printed", filePath);}
}public class PrinterService {final Logger logger;PrinterService(){this.logger = new Logger();}void print(String filePath) {// process print task...this.logger.log(filePath + " printed");}
}public class Logger {public log(String content){System.out.println(content);}
}public class EmailService {public void Send(String email, String subject, String content){System.out.println("Email %s has been sent to %s. ", subject, email);}
}

解决上面的方法可以是依赖注入,也可以通过类工厂的方法来解决。由于篇幅有限,我们在这里使用类工厂来展示解决方案。首先我们抽象出我们用到的组件的接口,然后我们通过类工厂来实现这些接口,最后通过类工厂来解决依赖问题。

下面是我们抽象出来的接口:

public inteface IPrinterService {void print(String filePath);
}public interface ILogger {void log(String content);
}public interface IEmailService {void send(String email, String subject, String content);
}

下面是类工厂的代码,虽然看上去很简单,但是通过类工厂,我们就解决了抽象到实现细节的问题,这使我们的业务逻辑独立于我们的依赖项。依赖项可以来自外部文件,对 Java 来说就是不同的 JAR 文件,对 .Net 来说可以是不同的 DLL。 

public class Factory {public static IPrinterService CreatePrinterService(){return new PrinterService();}public static ILogger CreateLogger() {return new Logger();}public static IEmailService CreateEmailService() {return new EmailService();}
}

下面是使用了类工厂以后的业务逻辑代码:

public Program {public static void main(String[] args) {var filePath = args[0];IPrinterService printerService = Factory.CreatePrinterService();printerService.print(filePath);IEmailService emailService = Factory.CreateEmailService();emailService.send("surfirst@example.com", "File printed", filePath);}
}public class PrinterService implements IPrinterService {final Logger logger;PrinterService(){this.logger = Factory.CreateLogger();}void print(String filePath) {// process print task...this.logger.log(filePath + " printed");}
}public class Logger implements ILogger {public log(String content){System.out.println(content);}
}public class EmailService implements EmailService {public void Send(String email, String subject, String content){System.out.println("Email %s has been sent to %s. ", subject, email);}
}

总述

没人写一款程序能完全遵守SOLID原则,甚至有些设计模式是违反SOLID原则。如何权衡就要看利是否大于弊。不足之处望指教。


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

相关文章

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…

1.Kafka下载安装

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

Kafka在Linux下载安装及部署

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

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

一、环境准备 首先JDK要在1.8及以上;然后安装对应版本的zookeeper。 本文以kafka2.7.2为例,关于如何找到kafka对应的zookeeper版本,参考我的这篇文章:如何确定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、消息队列的两种模式(1)点对点模式(2)发布/订阅模式 三、kafka基础架构 第二章 Kafka安装一、安装部署1、集群规划 二、集群部署1、下载地址(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? (Cross Site Request Forgery, 跨站域请求伪造)是一种网络的攻击方式,它在 2007 年曾被列为互联网 20 大安全隐患之一,也被称为“One Click Attack”或者Session Riding,通常缩写为CSRF或者XSRF&#xff…

Spring Security跨站请求伪造(CSRF)

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