我所理解的SOLID原则

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

      S.O.L.I.D 是面向对象设计(OOD)和面向对象编程(OOP)中的几个重要编码原则(Programming Priciple)的首字母缩写。

面向对象设计的原则
SRP The Single Responsibility Principle单一职责原则
OCP  The Open Closed Principle开放封闭原则
LSP The Liskov Substitution Principle里氏替换原则
ISP  The Interface Segregation Principle接口分离原则
DIP  The Dependency Inversion Principle依赖倒置原则

一、单一职责原则(SRP)

      从面向对象角度解释这个原则为:"引起类变化的因素永远不要多于一个。" 或者说 "一个类有且仅有一个职责"。这似乎不太好理解,特别是"引起类变化的因素永远不要多于一个。"这句话更是有点虚,让人有点摸不着头脑。

      我们通常都说“低耦合,高内聚”。在我看来,这里的"单一职责"就是我们通常所说的“高内聚”,即一个类只完成它应该完成的职责,不能推诿责任,也不可越殂代疱,不能成为无所不能的上帝类。如果你的团队中实施宽松的“代码集体所有权”,在编码的过程中出现许多人同时修改(维护)同一个类的现象,而且成员之间的沟通不够及时,主动和畅通的话,那么时间一长,就很可能出现“承担过多职责”的上帝类。这时,提炼基类/接口和提炼类重构将能帮助我们消除或减轻这种设计臭味。

看一个例子:


这是一个违反了“单一职责原则” 的类结构图。
这里,Rectangle类做了下面两件事:

  • 计算矩形面积;
  • 在界面(绘制设备)上绘制矩形;
并且,有两个应用使用了Rectangle类:
  • 计算几何应用程序(Computational Geometry Application)用这个类计算面积;
  • 图形程序(Graphical Application)用这个类在界面上绘制矩形;
这违反了SRP(单一职责原则)。因为Rectangle类做了两件事,在一个方法里它计算了面积,在另外一个方法了它返回一个表示矩形的GUI。这会带来一些有趣的问题:在计算几何应用程序中我们必须包含GUI。也就是在开发几何应用时,我们必须引用GUI库;图形应用程序中Rectangle类的变化可能导致计算几何应用程序的变化,编译和测试,反之亦然。那么,怎么修改才能让其符合单一职责原则呢?

答案是:拆分!拆分职责到两个不同的类中,如:

  • Rectangle: 这个类应该只定义Area()方法;
  • RectangleUI: 这个类应继承Rectangle类,并定义Draw()方法。

二、开放封闭原则 (OCP)

        从面向对象设计角度看,这个原则可以这么理解:"软件实体(类,模块,函数等等)应当对扩展开放,对修改闭合。" 通俗来讲,它意味着你(或者类的客户)应当能在不修改一个类的前提下扩展这个类的行为。在OOD里,对扩展开放意味着类或模块的行为能够改变,在需求变化时我们能以新的,不同的方式让模块改变,或者在新的应用中满足需求。

        也就是说,对扩展是开放的,而对修改是封闭的。我们通常都说:向系统中增加功能时应该只是添加新代码,而应该尽量少的修改原代码。在我看来,这就是遵循开放封闭原则所能带来的效果。曾经在网上看到过这样一句话“哪里变化,封装哪里”。这其实就是说,我们要将系统中可能变化的地方封装起来,即对修改封闭。同时,为了应对系统需求(功能)的扩展,需要抽象!

       这里抽象是关键。《设计模式》中的state模式和strategy模式是这个原则的最好体现。

举一个例子:


违反了开放封闭原则的类结构图。

客户端代码直接面向服务器端的具体实现编程,缺乏灵活性。这样如果服务器因为某些原因被其他服务器替换了,那么客户端调用服务器的代码也必须做相应的修改或替换。这其实就是”面向实现编程“的设计臭味!

那么,如何修改才能得到正确灵活的设计?

答案是:抽象!为服务器端的代码(类型)抽象出一个抽象基类(定义一组完成服务职责的最小接口)。

下面是正确的设计:


遵循开放封闭原则的类结构图。

       基本上,你抽象的东西是你系统的核心内容,如果你抽象得好,很可能增加一个新的服务器类型(扩展)只需要添加新类型(继承自AbstractServer即可)。因此代码要尽可能以抽象(这里的AbstractServer)为依据,这会允许你扩展抽象事物,定义一个新的实现而不需要修改任何客户端代码。即”面向接口编程,不要面向实现编程“!

三、Liskov's 替换原则(LSP)

    Liskov's 替换原则意思是:"子类型必须能够替换它们的基类型。"或者换个说法:"使用基类引用的地方必须能使用继承类的对象而不必知道它。" 这个原则正是保证继承能够被正确使用的前提。通常我们都说,“优先使用组合(委托)而不是继承”或者说“只有在确定是 is-a 的关系时才能使用继承”,因为继承经常导致”紧耦合“的设计。
    在基本的面向对象原则里,"继承"通常是"is a"的关系。如果"Developer" 是一个"SoftwareProfessional",那么"Developer"类应当继承"SoftwareProfessional"类。在类设计中"Is a"关系非常重要,但它容易冲昏头脑,导致使用错误的继承造成错误设计。

看一个最最经典的例子:


遵循Liskov替换原则的类结构图。

注:这里,KingFisher(翠鸟)类扩展了Bird基类,并继承了Fly()方法,这没有问题。

但是下面这个类结构图就存在设计上的问题:


违反Liskov替换原则的类结构图。

Ostrich(鸵鸟)是一种鸟,这毋庸置疑,并从Bird类继承,这从概念上说没有问题。但是鸵鸟它能飞吗?不能,那么这个设计就违反了LSP。因为在使用Bird的地方不一定能用Ostrich代替。所以,即使在现实中看起来没问题,在类设计中,Ostrich不应该从Bird类继承,这里应该从Bird中分离一个不会飞的类NoFlyBrid,Ostrich应该继承这个不会飞的鸟类NoFlyBrid。

为什么LSP如此重要?

  • 如果没有LSP,类继承就会混乱;如果子类作为一个参数传递给方法,将会出现未知行为;
  • 如果没有LSP,适用与基类的单元测试将不能成功用于测试子类;

四、接口分离原则(ISP)

      这个原则的意思是"客户端不应该被迫依赖于它们不用的接口。" 也就是说,一个接口或者类应该拥有尽可能少的行为(那么,什么叫尽可能少?就是少到恰好能完成它自身的职责),这也是保证“软件系统模块的粒度尽可能少,以达到高度可重用的目的。

     接口包含太多的方法会降低其可用性,像这种包含了无用方法的"胖接口"会增加类之间的耦合。如果一个类想实现该接口,那么它需要实现所有的方法,尽管有些对它来说可能完全没用,所以这样做会在系统中引入不必要的复杂度,降低代码的可维护性或鲁棒性。

     接口分离原则确保实现的接口有它们共同的职责,它们是明确的,易理解的,可复用的.

下面这个例子充分的说明了”接口应该仅包含必要的方法,而不该包含其它的“。如果一个接口包含了过多的方法,应该通过分离接口将其拆分。


这是一个违反接口分离原则的胖接口。

注意到IBird接口包含很多鸟类的行为,包括Fly()行为.现在如果一个Bird类(如Ostrich)实现了这个接口,那么它需要实现不必要的Fly()行为(Ostrich不会飞)。因此,这个"胖接口"应该拆分成两个不同的接口,IBird和IFlyingBird, 而IFlyingBird继承自IBird。如下图所示:


这样的话,重用将变得非常灵活:如果一种鸟不会飞(如Ostrich),那它实现IBird接口。如果一种鸟会飞(如KingFisher),那么它实现IFlyingBird。

因此,如果我们想要获得可重用的方案,就应当遵循接口分离原则,把接口定义成仅包含必要的部分,以便在任何需要该接口功能的地方复用这个接口。

五、依赖倒置原则(DIP)

         这个原则的意思是:高层模块不应该依赖底层模块,两者都应该依赖其抽象。其实又是”面向接口编程,不要面向实现编程“的内在要求。

我们考虑一个现实中的例子,来看看依赖倒置原则给我们软件带来的好处。 

你的汽车是由很多如引擎,车轮,空调和其它等部件组成,对吗?


注意:这里的 Car 就是高层模块;它依赖于抽象接口IToyotaEngine 和 IEighteenInchWheel.

而具体的引擎FifteenHundredCCEngine 属于底层模块,也依赖于抽象接口IToyotaEngine ;

具体的车轮 EighteenInchWheelWithAlloy同样属于底层模块,也依赖于抽象接口IEighteenInchWheel。

上面Car类有两个属性(引擎和车轮列表),它们都是抽象类型(接口)。引擎和车轮是可插拔的,因为汽车能接受任何实现了声明接口的对象,并且Car类不需要做任何改动。

        除SOLID原则外还有很多其它的面向对象原则。如:

  1. "组合替代继承":这是说相对于继承,要更倾向于使用组合;
  2. "笛米特法则":这是说"你的类对其它类知道的越少越好";
  3. "共同封闭原则":这是说"相关类应该打包在一起";
  4. "稳定抽象原则":这是说"类越稳定,越应该由抽象类组成";
当然,这些原则并不是孤立存在的,而是紧密联系的,遵循一个原则的同时也就遵循了另外一个或多个原则;反之,违反了其中一个原则也很可能同时就违反了另外一个或多个原则。 设计模式是这些原则在一些特定场景的应用结果。因此,可以把设计模式看作"框架",把OOD原则看作"规范"。 在学习设计模式的过程中,我们要经常性的反思,这个设计模式体现了面向对象设计原则中的哪个或哪一些原则。
特别是在重构实现模式,或重构趋向模式的过程中,我们更要结合SOLID原则思考代码在重构前后的区别,理解它的改进。我正在研读《重构与模式》一书,因此接下来我会结合例子记录自己的学习体会。
注:以上图片均来自《如何向妻子解释OOD》译文链接:http://www.cnblogs.com/niyw/archive/2011/01/25/1940603.html
<How I explained OOD to my wife> 原文链接:http://www.codeproject.com/Articles/93369/How-I-explained-OOD-to-my-wife

又及,还有两个常被提到的原则:

六、合成复用原则(CRP)

合成复用原则(Composite Reuse Principle,CRP),即优先使用委托而不是继承来重用已用功能(代码)。循序这一原则通常也是避免触犯里氏替换原则所要求的。

七、迪米特法则(LoD / LKP)

迪米特法则(Law Of  Demeter)又称最小知识原则(Least Knowledge Principle, LKP)。意思是一个对象应当对其它对象有尽量好的了解,即应该保持对象间有尽量少的相互作用是,使得对象(类)具有好的独立性,可测试性,也就易于维护。

关于“迪米特法则”的其它表述还有:只与你的朋友们通信,不要与“陌生人”说话。

设计模式中的Facade模式和Mediator模式就是使用了这一原则,降低模块间的耦合。



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

相关文章

浅谈 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…

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…