IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Python知识库 -> python:面向对象编程的设计原则之依赖倒置原则 -> 正文阅读

[Python知识库]python:面向对象编程的设计原则之依赖倒置原则

一,抽象与封装

coding 就是一个抽象的过程:在 OOP 中,我们将对象抽象为类。

  • 对象的状态与行为被抽象为类中的属性与方法。
  • 抽象的意义,就是为对象之的交互提供高效的接口。

封装就是在 coding 中隐藏数据与逻辑的过程:

  • 对象的状态和行为如何组织到类中,模块中的类该如何组织,更高层的代码该如何组织。
  • 抽象是多态和封装的基础,封装是接口的具体实现过程。

接口不一定需要由类来实现,只不过封装到类中有利于使用继承、多态、组合这些 OOP 基本特性以实现更高的代码可用性。

二,依赖倒置原则

(一)依赖正置

我们不断在强调 OOP 的软件设计应该考虑到后期可能出现的功能扩展需求,当我们的软件足够复杂之后,代码就会出现高低层次之分。

这个高低层次划分没有明确的界限,但可以肯定的是,绝对存在高层次代码对低层次代码的依赖。

低层次的代码可以是第三方 API,也可以是其他工作组定义的细节实现,高层次的代码通过继承、组合等方式依赖于它们提供的功能。

举个例子🌰:

class FXConverter:  # 创建低层转换器类
    def convert(self, from_currency, to_currency, amount):
        print(f'{amount} {from_currency} = {amount * 1.2} {to_currency}')
        return amount * 1.2


class App:          # 创建高层应用类
    def start(self):
        converter = FXConverter()
        converter.convert('EUR', 'USD', 100)


if __name__ == '__main__':
    app = App()
    app.start()

>>>
100 EUR = 120.0 USD

这使得高层代码严重依赖于低层代码,虽说不至于达到硬编码那种耦合程度,但在这种依赖“正置”的情况下,面对可能不够稳定的或者不可控的低层代码时,高低层的交互耦合度还是显得有点高。

  • 如果低层被破坏,则高层功能无法正确实现。
  • 如果高层需要使用其他 API,则需要修改高层本身代码。

(二)依赖倒置原则

我们需要一种方法来进一步降低耦合度,比如就像依赖倒置原则( Dependency Inversion Principle,DIP)要求的这样:

  • 高层不应该从低层导入任何东西,两者都应该依赖于抽象(例如,接口)。
  • 抽象不应该依赖于细节。细节应该依赖于抽象。

在设计高层模块和低层模块之间的交互时,应该抽象它们之间的交互,让高层代码和底层代码都通过这层抽象来交互,避免了直接的交互动作,两者之间的耦合度自然也就降低了。

这个抽象可以通过抽象基类来实现:

from abc import ABC, abstractmethod

class CurrencyConverter(ABC):
    @abstractmethod
    def convert(self, from_currency, to_currency, amount) -> float:
        pass

而正是这层抽象,让原本从高到低的正向依赖,转为高层依赖抽象且低层也依赖抽象:

class OldConverter(CurrencyConverter):
    def convert(self, from_currency, to_currency, amount) -> float:
        print('Converting currency using OldConverter API, date: 2020-12-18')
        print(f'{amount} {from_currency} = {amount * 0.8156} {to_currency}')
        return amount * 0.8156


class NewConverter(CurrencyConverter):
    def convert(self, from_currency, to_currency, amount) -> float:
        print('Converting currency using NewConverter API, date: 2022-04-06')
        print(f'{amount} {from_currency} = {amount * 0.9158} {to_currency}')
        return amount * 0.9158


class App:
    def __init__(self, converter: CurrencyConverter):   # 注意:这里的converter是一个接口,不是一个细节实现
        self.converter = converter

    def start(self):
        self.converter.convert('USD', 'EUR', 100)

从而实现更加健壮的代码:

if __name__ == '__main__':
    converter_one = OldConverter()
    converter_two = NewConverter()

    app = App(converter_one)
    app.start()
    app = App(converter_two)
    app.start()

>>>
Converting currency using OldConverter API, date: 2020-12-18
100 USD = 81.56 EUR
Converting currency using NewConverter API, date: 2022-04-06
100 USD = 91.58 EUR

尽管 DIP 非常有用,但代码经过LSP、OCP、ISP 和 SRP 考虑后,已经拥有了相当的可重用性与健壮性了,这使得在实际中遵守 DIP 的代码就不太多。

Dependency Inversion in Python
OOP - Best way to populate Object

  Python知识库 最新文章
Python中String模块
【Python】 14-CVS文件操作
python的panda库读写文件
使用Nordic的nrf52840实现蓝牙DFU过程
【Python学习记录】numpy数组用法整理
Python学习笔记
python字符串和列表
python如何从txt文件中解析出有效的数据
Python编程从入门到实践自学/3.1-3.2
python变量
上一篇文章      下一篇文章      查看所有文章
加:2022-04-09 18:19:02  更:2022-04-09 18:21:39 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/15 18:47:58-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码