面向对象设计之魂(六大原则)

2023-12-12 20:39

本文主要是介绍面向对象设计之魂(六大原则),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

[版权申明] 非商业目的注明出处可自由转载
博文地址:https://blog.csdn.net/ShuSheng0007/article/details/87901626
出自:shusheng007

文章目录

  • 前言
  • 六大原则
    • 1 单一职责(Single Responsibility Principle)
    • 2 开闭原则(Open Close Principle)
    • 3 里氏替换原则(Liskov Substitution Principle)
    • 4 依赖倒置原则(Dependence Inversion Principle)
    • 5 接口隔离原则(Interface Segregation Principle)
    • 6 迪米特原则(Law of Demeter 又名Least Knowledge Principle)
  • 总结

前言

常言道实践是需要理论来指导的,而理论又是需要实践来检验和修正的,理论和实践就这样相互促进,最后将一个领域推向新的高度。从面向对象编程的出现到现在好像已经有半个世纪了(于1950s第一次出现在MIT),所以这六大原则是在无数先辈的理论与实践中产生的。
身为一名主要使用面向对象编程软件从业员(码农),这六大原则是必须要掌握的,它就是设计模式的理论,设计模式是它的实践。

六大原则

这六大原则应该成为你在日常开发中的理论指导,只要你或多或少的遵循这六大设计原则,那么写出的代码就不会太烂,慢慢的你会发现你竟然理解了那些吊炸天的设计模式意图及设计思路。

软件的面向对象开发一般提倡遵循SOLID原则,这个单词就是我们这里前5个原则的首字母缩写。

1 单一职责(Single Responsibility Principle)

这个原则顾名就可以思义,就是一个类应该只负责一个职责,术语叫:仅有一个引起其变化的原因。简单点说:一个类中应该是一组相关性很高的函数及数据的封装,个中含义请自行意会。看起来简单,但是做起来就难了,这可能是六大原则中最难以熟练掌握的一个原则了,它高度依赖程序员的自身素质及业务场景。

例如两个男性码农能为是否应该将一个函数写进某个类里面吵一天,最后谁也没有说服谁,最后他两成了好基友

其实单一职责不仅在类中遵循,在方法中也应该遵循,下面是几个判断是否违反原则的参考:

  • 一个方法中if else等条件语句特别多
  • 一个类中依赖了很多其他的类
  • 一个类根据外部出入的值执行不同的任务

2 开闭原则(Open Close Principle)

它是面向对象最重要的设计原则,由Bertrand Meyer(勃兰特.梅耶)在1988年出版的《面向对象软件构造》。中提出的。
在这里插入图片描述
本尊照片,图片来源

定义如下

开闭原则(Open-Closed Principle, OCP):一个软件实体应当对扩展开放,对修改关闭。即软件实体应尽量在不修改原有代码的情况下进行扩展。

提倡一个类一旦开发完成,后续增加新的功能就不应该通过修改这个类来完成,而是通过继承,增加新的类。
大家想必都听过软件需求不断变化的那个段子,在软件开发这个行当唯一不变的就是变化本身。那为什么应该对修改关闭呢,因为你一旦修改了某个类就有可能破坏系统原来的功能,就需要重新测试。其实我知道你们此刻在想什么,回忆一下自己的日常工作,有几个遵守了这个原则,都是需求来了就找到原来的类,进去改代码呗,_。看看有指导原则尚且如此,没有的话就更加乱套了。

那么是不是就一定不能修改原来的类的,当然不是了,我们都是成年人了,要清楚的认识到,这个世界不是非黑即白的。当我们发现原来的类已经烂到家了,当然在有条件的情况下及时重构,避免系统加速腐败。

违反此原则的参考:

  • 增加需求时总是需要不断修改对应的代码

3 里氏替换原则(Liskov Substitution Principle)

这个原则的的提出则可以是一位女性Barbara Liskov,下图为她2010年的照片,现在应该还健在吧,其实计算机这个行当的从业人员比较幸福,我们的祖师爷基本都健在,不像一些其他行业,都死了不知道多少年了,显得很神秘。
在这里插入图片描述
定义如下:

里氏代换原则(Liskov Substitution Principle, LSP):所有引用基类(父类)的地方必须能透明地使用其子类的对象。

简单点说,一个软件系统中所有用到一个类的地方都替换成其子类,系统应该仍然可以正常工作。这个原则依赖面向对象的继承特性和多态特性,这个原则我们有意无意中使用的就比较多了。因为一个优秀的程序员一定面向抽象(接口)编程的,如果你不是,说明你还有很大的进步空间。

例如我们有如下的代码,一个图形的基类Shap,以及它的两个子类RectangleTriangle,安装里式替换原则,所有使用Shape的地方都可以安全的替换成其子类。

//基类
public abstract class Shape {public abstract void draw();
}
//子类矩形
public class Rectangle extends Shape {@Overridepublic void draw() {System.out.println("绘制矩形");}
}
//子类三角形
public class Triangle extends Shape {@Overridepublic void draw() {System.out.println("绘制三角形");}
}

写一个使用Shape类的函数

public static void main(String[] args) {//使用Shape的子类Triangle 的实例来替换Shape的实例,程序工作正常drawShape(new Triangle());
}
private static void drawShape(Shape shape){System.out.println("开始画图");shape.draw();System.out.println("结束画图");
}

输出结果:

开始画图
绘制三角形
结束画图

如上代码所示:本来drawShape()函数需要一个Shape的实例,而我们却传给他一个其子类的实例,但是它正常工作了。我们使用Shape的子类Triangle的实例来替换Shape的实例,程序工作正常。这个原则也非常重要而常用,面向抽象编程。

违反此原则的参考:

  • 代码中使用了isinstance之类的之类判定类型,然后强制转换后使用里面的方法。
  • 类里面存在接口或者其继承的抽象类的方法的空实现,类似下面这样的
    @Overridepublic void laiDaYiMa() {//老子不来大姨妈,所以方法置空,啥也不干!}

4 依赖倒置原则(Dependence Inversion Principle)

这个原则的提倡者正是大名鼎鼎的 Robert C. Martin,人称Bob大叔,其应该是面向对象编程中最重要的原则了吧。
在这里插入图片描述
定义

依赖倒转原则(Dependency Inversion Principle, DIP):抽象不应该依赖于细节,细节应当依赖于抽象。换言之,要针对接口编程,而不是针对实现编程。

关键点:

  1. 高层模块不应该依赖低层模块,两者都应该依赖其抽象
  2. 抽象不应该依赖细节
  3. 细节应该依赖抽象

看到上面的介绍是不是已经懵逼了,反正我刚开始学习编程(半路大龄非科班出身)的时候是彻底懵逼的。因为这个概念人家是从软件设计的角度说的,我们应该将其对应到我们具体的实践当中去理解,例如Java领域

抽象:java中的抽象类或者接口 (如上面代码中的Shape 抽象类)
细节:java中的具体实现类(如上面代码中的Rectangle 和Triangle 实体类)
高层模块:java中的调用类(例如上面代码中drawShape(Shape shape)函数的类)
低层模块:java中的实现类(细节)

依赖倒置又叫依赖倒转,关键在倒置上,啥叫倒置,那不倒置的时候是什么样的?如下面图所示

正常情况下:调用类(高层模块)应该依赖具体实现类(低层模块实现细节)

倒置后:高层模块与低层模块都依赖了实现类的接口(低层模块的细节抽象),底层模块的依赖箭头向上了,所以叫依赖倒置了。
在这里插入图片描述

例如菜鸟程序员(牛翠花)会这么写代码

    private static void drawRectangle (Rectangle rectangle){        rectangle.draw();}private static void drawTriangle  (Triangle triangle){        triangle.draw();}

而老鸟(王二狗)则会

    private static void drawShape(Shape shape){shape.draw();}

那么菜鸟的代码会有什么问题呢,假设现在产品经理觉得矩形不好看,让牛翠花将矩形换成五角形,那么牛翠花就要同时修改调用类和增加一个绘制类,而王二狗的代码只需要增加一个五角形的绘制类,这就遵循了开关闭原则

所以我们要对接口编程,举几个具体的例子:声明方法参数的类型,实例变量的类型,方法的返回值类型,类型强制转换等等场景。

牛翠花的代码直接依赖了实现细节,而王二狗的代码依赖的是实现细节的抽象(依赖倒置了)。刚入门时候我们都是牛翠花,但是几年后有的人变成了王二狗,有的人仍然是牛翠花。。。

5 接口隔离原则(Interface Segregation Principle)

接口隔离原则(Interface Segregation Principle, ISP):使用多个专门的接口,而不使用单一的总接口,即客户端不应该依赖那些它不需要的接口。

其实这个原则是很容易理解的,就是让调用者依赖的接口尽可能的小。例如人类分男人和女人,男人和女人都要吃饭,但是只有女人每个月来大姨妈,那么如果你设计一个接口里面除了吃饭还有来大姨妈同时给男人和女人用就不合适了。

interface IHuman{void eat();void sleep();void laiDaYiMa();//来大姨妈
}

这你让男人情何以堪,万一有个菜鸟程序员抽风了,直接给把来大姨妈的方法实现了,那后果就。。。

//男人类不需要接口中的laiDaYiMa方法
class man implements IHuman{@Overridepublic void eat() {        }@Overridepublic void laiDaYiMa() {//老子不来大姨妈,所以方法置空,啥也不干!}
}
class woman implements IHuman{@Overridepublic void eat() {        }@Overridepublic void laiDaYiMa() {System.out.println("王二狗,给老娘倒一杯热水");}
}

上面的例子就违反了接口隔离原则,正确的做法是申明两个接口,使接口保持最小

interface IHuman{void eat();
}
interface ISpecialForWoman{void laiDaYiMa();//来大姨妈
}

男人只实现IHuman,女人实现IHumanISpecialForWoman

class man implements IHuman{@Overridepublic void eat() {}
}
class woman implements IHuman,ISpecialForWoman{@Overridepublic void eat() {}@Overridepublic void laiDaYiMa() {System.out.println("王二狗,给老娘倒一杯热水");}
}

6 迪米特原则(Law of Demeter 又名Least Knowledge Principle)

迪米特法则来自于1987年美国东北大学(Northeastern University)一个名为“Demeter”的研究项目,又称最少知识原则(LeastKnowledge Principle, LKP),其定义如下:

迪米特法则(Law of Demeter, LoD):一个软件实体应当尽可能少地与其他实体发生相互作用。

一个类应该对自己需要调用的类知道得最少,类的内部如何实现、如何复杂都与调用者或者依赖者没关系,调用者或者依赖者只需要知道他需要的方法即可,其他的我一概不关心。

总结

以上六大原则全部是以构建灵活可扩展可维护的软件系统为目的的,所以说它的重要性是高于设计模式的,也应该是程序员时刻印在脑子里的,设计模式只是它的具体实践而已。

我将会逐步撰写一些简单易懂的设计模式相关的文章,对设计模式感兴趣的同学欢迎关注博主,带你装b带你飞

这篇关于面向对象设计之魂(六大原则)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/485866

相关文章

不懂推荐算法也能设计推荐系统

本文以商业化应用推荐为例,告诉我们不懂推荐算法的产品,也能从产品侧出发, 设计出一款不错的推荐系统。 相信很多新手产品,看到算法二字,多是懵圈的。 什么排序算法、最短路径等都是相对传统的算法(注:传统是指科班出身的产品都会接触过)。但对于推荐算法,多数产品对着网上搜到的资源,都会无从下手。特别当某些推荐算法 和 “AI”扯上关系后,更是加大了理解的难度。 但,不了解推荐算法,就无法做推荐系

怎么让1台电脑共享给7人同时流畅设计

在当今的创意设计与数字内容生产领域,图形工作站以其强大的计算能力、专业的图形处理能力和稳定的系统性能,成为了众多设计师、动画师、视频编辑师等创意工作者的必备工具。 设计团队面临资源有限,比如只有一台高性能电脑时,如何高效地让七人同时流畅地进行设计工作,便成为了一个亟待解决的问题。 一、硬件升级与配置 1.高性能处理器(CPU):选择多核、高线程的处理器,例如Intel的至强系列或AMD的Ry

基于51单片机的自动转向修复系统的设计与实现

文章目录 前言资料获取设计介绍功能介绍设计清单具体实现截图参考文献设计获取 前言 💗博主介绍:✌全网粉丝10W+,CSDN特邀作者、博客专家、CSDN新星计划导师,一名热衷于单片机技术探索与分享的博主、专注于 精通51/STM32/MSP430/AVR等单片机设计 主要对象是咱们电子相关专业的大学生,希望您们都共创辉煌!✌💗 👇🏻 精彩专栏 推荐订阅👇🏻 单片机

SprinBoot+Vue网络商城海鲜市场的设计与实现

目录 1 项目介绍2 项目截图3 核心代码3.1 Controller3.2 Service3.3 Dao3.4 application.yml3.5 SpringbootApplication3.5 Vue 4 数据库表设计5 文档参考6 计算机毕设选题推荐7 源码获取 1 项目介绍 博主个人介绍:CSDN认证博客专家,CSDN平台Java领域优质创作者,全网30w+

JVM内存调优原则及几种JVM内存调优方法

JVM内存调优原则及几种JVM内存调优方法 1、堆大小设置。 2、回收器选择。   1、在对JVM内存调优的时候不能只看操作系统级别Java进程所占用的内存,这个数值不能准确的反应堆内存的真实占用情况,因为GC过后这个值是不会变化的,因此内存调优的时候要更多地使用JDK提供的内存查看工具,比如JConsole和Java VisualVM。   2、对JVM内存的系统级的调优主要的目的是减少

单片机毕业设计基于单片机的智能门禁系统的设计与实现

文章目录 前言资料获取设计介绍功能介绍程序代码部分参考 设计清单具体实现截图参考文献设计获取 前言 💗博主介绍:✌全网粉丝10W+,CSDN特邀作者、博客专家、CSDN新星计划导师,一名热衷于单片机技术探索与分享的博主、专注于 精通51/STM32/MSP430/AVR等单片机设计 主要对象是咱们电子相关专业的大学生,希望您们都共创辉煌!✌💗 👇🏻 精彩专栏 推荐订

Spring的设计⽬标——《Spring技术内幕》

读《Spring技术内幕》第二版,计文柯著。 如果我们要简要地描述Spring的设计⽬标,可以这么说,Spring为开发者提供的是⼀个⼀站式的轻量级应⽤开发框架(平台)。 作为平台,Spring抽象了我们在 许多应⽤开发中遇到的共性问题;同时,作为⼀个轻量级的应⽤开发框架,Spring和传统的J2EE开发相⽐,有其⾃⾝的特点。 通过这些⾃⾝的特点,Spring充分体现了它的设计理念:在

开题报告中的研究方法设计:AI能帮你做什么?

AIPaperGPT,论文写作神器~ https://www.aipapergpt.com/ 大家都准备开题报告了吗?研究方法部分是不是已经让你头疼到抓狂? 别急,这可是大多数人都会遇到的难题!尤其是研究方法设计这一块,选定性还是定量,怎么搞才能符合老师的要求? 每次到这儿,头脑一片空白。 好消息是,现在AI工具火得一塌糊涂,比如ChatGPT,居然能帮你在研究方法这块儿上出点主意。是不

创业者该如何设计公司的股权架构

本文来自七八点联合IT橘子和车库咖啡的一系列关于设计公司股权结构的讲座。 主讲人何德文: 在公司发展的不同阶段,创业者都会面临公司股权架构设计问题: 1.合伙人合伙创业第一天,就会面临股权架构设计问题(合伙人股权设计); 2.公司早期要引入天使资金,会面临股权架构设计问题(天使融资); 3.公司有三五十号人,要激励中层管理与重要技术人员和公司长期走下去,会面临股权架构设计问题(员工股权激

ffmpeg面向对象-待定

1.常用对象 rtsp拉流第一步都是avformat_open_input,其入参可以看下怎么用: AVFormatContext *fmt_ctx = NULL;result = avformat_open_input(&fmt_ctx, input_filename, NULL, NULL); 其中fmt_ctx 如何分配内存的?如下 int avformat_open_input(