面向对象设计 SOLID 原则和python例子

news/2023/5/28 8:38:47

面向对象设计 SOLID 原则共有 5 个,它们分别是:

1、依赖倒置原则 (Dependency Inversion Principle, DIP) :指的是高层模块 (high-level modules) 不应该依赖于低层模块 (low-level modules), 两者都应该依赖于抽象 (abstractions)。也就是说要以抽象为基础,而不是以实现为基础来进行编程

我个人的理解是,要先抽象出一个接口类,然后接口不实现具体的实现,但要定义输入的参数,起到让调用的人作为参考的作用。


# 一个例子:class LowLevelModule:def low_level_method(self):passclass HighLevelModule:def __init__(self):self.low_level_module = LowLevelModule()def high_level_method(self):self.low_level_module.low_level_method()# 在上面的代码中,HighLevelModule 类依赖于 LowLevelModule 类。为了遵循 DIP,我们应该将这种依赖关系反转过来:class LowLevelModule:def low_level_method(self):passclass HighLevelModule:def __init__(self, low_level_module):self.low_level_module = low_level_moduledef high_level_method(self):self.low_level_module.low_level_method()# 在这个例子中,HighLevelModule 类不再依赖于具体的实现类 LowLevelModule,而是依赖于抽象(接口)。

2、里氏替换原则 (Liskov Substitution Principle, LSP) :指的是如果一个程序中使用的是基类 (base class) 的对象,那么在不改变程序正确性的前提下,这个程序中基类对象的地方都可以使用其子类 (subclass) 对象来替换

我个人的理解是,要能够像调用父类一样调用子类,例如父类有一个方法是怎么调用的,子类也要有这个方法,并且是一样的调用这个方法


# 以下是一个例子:class Shape:def area(self):passclass Rectangle(Shape):def __init__(self, width, height):self.width = widthself.height = heightdef area(self):return self.width * self.heightclass Square(Rectangle):def __init__(self, side):self.width = sideself.height = sidedef calculate_area(shape: Shape) -> float:return shape.area()rectangle = Rectangle(2, 3)
print(calculate_area(rectangle))  # 6square = Square(2)
print(calculate_area(square))  # 4
# 在上面的代码中,我们定义了一个 Shape 类和两个子类 Rectangle 和 Square。
# 这两个子类都可以替换成基类 Shape,并且都可以正常工作。# 在函数 calculate_area 中,我们传入了一个 Shape 类型的参数,这个函数可以处理任何继承
# 自 Shape 的子类,而不需要考虑具体的子类是什么,这就是里氏替换原则的体现。# 里氏替换原则的要求是,子类需要满足的条件是,不破坏父类的约束条件,并且满足自己的约束条件。

3、开放封闭原则 (Open-Closed Principle, OCP) :指的是一个类或模块应该对扩展开放,对修改封闭。也就是说,当需要新增功能时,应该通过增加新的代码来实现,而不是修改现有的代码。

我个人的理解是:由于一个类可能会被多个地方都使用到,如果随便对这个类进行修改,那么可能很多引用这个类的地方都需要进行修改,这个工作量是很大的,而且还容易没有全部地方都进行修改,从而引发 BUG。因此可以选择对这个类进行继承,将新功能在继承的子类里进行实现。也可以写一个名字跟原来的接口的名字不同的新接口。个人感觉重新写一个新名字的接口的方法更简单,但是如果要增加的新接口很多的话,还是使用子类继承更好。


以下是一个例子:class Shape:def area(self):passclass Rectangle(Shape):def __init__(self, width, height):self.width = widthself.height = heightdef area(self):return self.width * self.heightclass Circle(Shape):def __init__(self, radius):self.radius = radiusdef area(self):return 3.14 * self.radius ** 2class ShapeCalculator:def calculate_area(self, shape):return shape.area()calculator = ShapeCalculator()
rectangle = Rectangle(2, 3)
print(calculator.calculate_area(rectangle)) # 6
circle = Circle(2)
print(calculator.calculate_area(circle)) # 12.56# 在上面的代码中,我们定义了一个基类 Shape, 两个子类 Rectangle 和 Circle。
# 在类 ShapeCalculator 中,我们有一个函数 calculate_area,该函数可以处理任何继承
# 自 Shape 的子类,而不需要考虑具体的子类是什么,这样我们可以在不修改现有代码的情况
# 下新增新的图形类型,这就是开放封闭原则的体现。# 这种设计方式可以保证现有代码不会因新增功能而改变,从而降低维护代码的成本。

4、接口隔离原则 (Interface Segregation Principle, ISP) :指的是客户端不应该依赖它不需要的接口,即一个类对另一个类的依赖应该建立在最小的接口上。

我个人的理解是:假如一个接口类有很多的接口,但是实现这个接口类的具体实现类,其实有很多接口是使用不到的,因此如果要一一实现这些接口,既无法具体实现,也没有必要耗费大量的时间精力去实现这些接口,因此需要将接口类尽量分成多个接口类,每个接口类都比较精简,这样在实现的时候,就可以避免要去实现它不需要实现的接口。


# 以下是一个例子:class Document:def __init__(self, content):self.content = contentdef save(self):passdef print(self):passdef fax(self):passclass SimplePrinter:def print(self, document: Document):print(document.content)class Fax:def fax(self, document: Document):print(f"Faxing the document: {document.content}")# 在上面的代码中,我们定义了一个Document类,它包含三个方法:save,print,fax。
# 然而,并不是所有的客户端都需要使用这三个方法,比如 SimplePrinter只需要使用
#  print 方法,而不需要使用 save, fax 方法,这样就导致了客户端不必要的依赖。# 为了遵循 ISP,我们应该将这些接口拆分为更小的接口,比如:class PrintableDocument(ABC):@abstractmethoddef print(self):passclass SaveableDocument(ABC):@abstractmethoddef save(self):passclass FaxableDocument(ABC):@abstractmethoddef fax(self):passclass Document(PrintableDocument, SaveableDocument, FaxableDocument):def __init__(self, content):self.content = contentdef save(self):passdef print(self):print(self.content)def fax(self):passclass SimplePrinter:def print(self, document: PrintableDocument):print(document.content)class Fax:def fax(self, document: FaxableDocument):print(f"Faxing the document: {document.content}")
# 这样,我们就将 Document 类拆分成了三个更小的接口

5、单一职责原则:单一职责原则 (Single Responsibility Principle, SRP) :指的是一个类应该只有一个引起它变化的原因。也就是说,一个类只应该有一个负责其中的逻辑。

我个人的理解是:如果一个类需要实现多个职责,那么可能会导致这个类的功能不够明确,在实现时会增加很多不该在这个类中实现的功能。


# 以下是一个例子:class Employee:def __init__(self, name, salary):self.name = nameself.salary = salarydef increase_salary(self, percent):self.salary = self.salary + (self.salary * percent) / 100def save_employee(self):# save the employee to the databasepassdef send_email(self):# send email to the employeepass
# 在上面的代码中,类 Employee 负责三种职责:薪水计算、存储到数据库和发送电子邮件。# 为了遵循 SRP,我们应该将这些职责拆分成不同的类,比如:class Employee:def __init__(self, name, salary):self.name = nameself.salary = salaryclass SalaryCalculator:def increase_salary(self, employee: Employee, percent):employee.salary = employee.salary + (employee.salary * percent) / 100class EmployeeDB:def save_employee(self, employee: Employee):# save the employee to the databasepassclass EmailSender:def send_email(self, employee: Employee):# send email to the employeepass# 这样每个类只负责一个单一的职责,使得类更加简单,容易维护,这就是单一职责原则的体现。

这几个原则之间有没有互相矛盾的地方?

这几个原则之间并不会互相矛盾,而是相互补充和协同工作。

依赖倒置原则 (Dependency Inversion Principle, DIP) 强调的是高层模块不应该依赖低层模块,

而是应该依赖抽象。这个原则可以和单一职责原则 (Single Responsibility Principle, SRP) 协同工作,

因为如果低层模块有多个职责,那么就会增加高层模块的依赖。

里氏替换原则 (Liskov Substitution Principle, LSP) 强调的是子类应该能够替换父类。这个原则可以和

开放封闭原则 (Open-Closed Principle, OCP) 协同工作,因为如果父类是可扩展的,那么子类就可以扩展

父类的行为,而不会破坏程序的正确性。

接口隔离原则 (Interface Segregation Principle, ISP) 强调的是客户端不应该依赖它不需要的接口。

这个原则可以和依赖倒置原则 (Dependency Inversion Principle, DIP) 协同工作,因为如果低层模块的

接口不是客户端需要的,那么就会增加高层模块的依赖。

总之,这些原则是相互补充和协同工作的,它们的目的都是为了让代码更加简单,易于维护和扩展。遵循这些

原则可以使得代码具有高内聚性和低耦合性,这样可以降低程序的复杂性,提高程序的可维护性和可扩展性。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.exyb.cn/news/show-4563209.html

如若内容造成侵权/违法违规/事实不符,请联系郑州代理记账网进行投诉反馈,一经查实,立即删除!

相关文章

HIT ICS大作业

目录 目 录 第1章 概述 1.1 Hello简介 1.2 环境与工具 1.3 中间结果 1.4 本章小结 第2章 预处理 2.1 预处理的概念与作用 2.2在Ubuntu下预处理的命令 2.3 Hello的预处理结果解析 2.4 本章小结 第3章 编译 3.1 编译的概念与作用 3.2 在Ubuntu下编译的命令 3.3 …

三十二、Kubernetes中Service详解、实例第二篇

1、概述 在kubernetes中,pod是应用程序的载体,我们可以通过pod的ip来访问应用程序,但是pod的ip地址不是固定的,这也就意味着不方便直接采用pod的ip对服务进行访问。 为了解决这个问题,kubernetes提供了Service资源&…

RK987三模机械键盘win和alt键互换

fn加s 切换window fn加a 切换mac fn加win 是锁住/解锁 win键

RK系列无线键盘-RK100无限键盘使用说明书

RK系列无线键盘-RK100无限键盘使用说明书 1、 2、 3、 4、 5、 6、 7、 8、 9、

RK988键盘切换蓝牙模式

1、背面开关选择ON 2、短按FnTAB 切换蓝牙,右上角灯闪烁3次 3、短按FnQ/W/E其中之一,选择需要连接的其中一个蓝牙设备,可以连接3台蓝牙设备,右上角灯闪烁3次 4、长按FnQ/W/E其中之一,Q/W/E按键之一会闪烁,已经进入蓝…

RK100键盘说明书

适用于RK100键 RK100 说明书 版本:蓝牙USB双模,USB蓝牙2.4G三模,有线 属性:RGB,单色,无背光 在线说明书地址

rk键盘快捷键快捷键不一致_使用键盘快捷键立即搜索您的终端历史记录

rk键盘快捷键快捷键不一致Everyone who regularly uses the command line has at least one long string they type regularly. Instead of entering all that again and again, quickly search your history to find the complete command. 定期使用命令行的每个人都有至少一个…

rk键盘快捷键快捷键不一致_为什么其他键盘语言的键盘快捷键和可访问性很少起作用...

rk键盘快捷键快捷键不一致Using keyboard shortcuts are important both if you have accessibility problems but also just in general as it is much more precise using the keyboard than reaching out for the mouse and pointing.使用键盘快捷键不仅在您遇到可访问性问题…

使用BDE数据库引擎的应用软件出现Insufficient disk space的解决方法

问题描述: 某医院收费软件,在运行时候,最近突然偶尔会出现下图的错误提示,刚开始还以为是c盘空间不足了,检查后发现还有20多G的剩余空间,显然不是没有硬盘空间的原因。 究其原因: 查阅相关资料…

BDE Installer for RAD Studio

BDE Installer for RAD Studio BDE安装程序是一个易于安装BDE的工具。BDE或Borland数据库引擎是连接数据库和执行数据事务的最重要的海豚计算机之一。尽管这家公司已经破旧不堪,但出于某些原因,仍有一些计划可以使用这家公司。另一方面,你的营…

bde连接mysql设置,delphi通过BDE方式连接数据库以及程序Demo

1、设置BDE连接2、将TQuery组件放入程序Form窗体3、设置TQuery属性4、程序Demowith Query5 do begin Query5.Close; Query5.SQL.clear; str:select *from msn where name:name; Query5.SQL.add(str); Query5.ParamByName(name).value:TreeView1.Sel…

联通数据采集交换平台BDE的配置

1,数据管理点击数据编目管理的中数据库资源中添加需要扫入的表信息(Oracle和hive都需要) 2,在任务配置界面添加需要配置的任务 3,zbg开头的都是33库的(dwe) zb,zba 为一库&#xf…

delphi bde mysql_Delphi- 连接MySQL数据库BDE

Delphi使用ADO可以连接MSSQL和ACCESS,但似乎不能连接MYSQL和ORACEL,如果要连接MYSQL和ORACLE得使用BDE。一、连接方法首先得先安装mysql驱动程序_mysql-connector-odbc-5.1.6-win32,然后点控件面板->管理工具->数据源 (ODBC)点系统DNS&…

元宇宙iwemeta: 2021年云计算行业发展研究报告

笔者认为:云计算产业还处于产业化的早期阶段,对于阿里云,华为云来说,追赶世界一流技术,不仅需要技术、资金,更需要世界一流的云计算人才。这才是追赶世界一流企业的根本。 华为云值得期待,聚集了…

[推荐]一口气说出前后端 10 种鉴权方案~

在介绍鉴权方法之前,我们先要了解的是:什么是认证、授权、鉴权、权限控制以及他们之间的关系,有了他们做铺垫,那么我们才能做到从始至终的了解透彻 ~ 什么是认证? 认证(Identification) 是指根据声明者所特有的识别信…

一文教你彻底搞定前后端所有鉴权方案,让你不再迷惘

点击上方 前端Q,关注公众号回复加群,加入前端Q技术交流群作者:易师傅https://juejin.cn/post/7129298214959710244前言还记得之前在面试的时候,有一位面试官就问了,关于前端鉴权这块,Token、Cookie、Sessio…

前后端鉴权方案

链接:https://mp.weixin.qq.com/s/wnkq4gQuVGp4_9rQ4_t8aA 什么是认证:根据声明者的识别信息,确认身份(根证明自己类似) 什么是授权:资源所有者 赋予执行者指定范围的资源操作权限(银行卡、门…

Ubuntu下源码编译VirtualBox一 —— 源码下载

VirtualBox想必大家都不陌生,做Linux开发的尤其是嵌入式Linux开发的人应该基本都知道或玩过VMware和VirtualBox。但通常都是为了在Windows电脑上能够使用Linux环境、即在Windows环境下通过下载可执行文件安装的VirtualBox。本文介绍在Linux环境(Ubuntu 2…

假期余额不足,说一下这个假期做的事

国庆8天过的真快,明天就要去上班了。这期间没出去,做完了三件事。 1、www.learnfk.com 乌鸦教程网历时一年断断续续终于完成第一版。从翻译,到人工编辑,都是体力活,真心累。下一步打算过一个月后现继续完善内容。布局…