【新人系列】Python 入门(二十六):常见设计模式

devtools/2025/1/19 4:02:20/

✍ 个人博客:https://blog.csdn.net/Newin2020?type=blog
📝 专栏地址:https://blog.csdn.net/newin2020/category_12801353.html
📣 专栏定位:为 0 基础刚入门 Python 的小伙伴提供详细的讲解,也欢迎大佬们一起交流~
📚 专栏简介:在这个专栏,我将带着大家从 0 开始入门 Python 的学习。在这个 Python 的新人系列专栏下,将会总结 Python 入门基础的一些知识点,方便大家快速入门学习~
❤️ 如果有收获的话,欢迎点赞 👍 收藏 📁 关注,您的支持就是我创作的最大动力 💪

1. 设计模式

1.1 介绍

设计模式是一种解决特定问题的经验、一种通用的解决方案,它有如下优点:

  • 提高代码可重用性(重点)
  • 提供代码的扩展性(重点)
  • 提高可读性
  • 提高软件的性能、效率
  • 提高代码的维护性

1.2 设计模式分类

设计模式通常根据其目的和用途进行分类,常见的分类包括:

  • 创建型模式:工厂方法模式、抽象工厂模式、单例模式等
  • 结构型模式:适配器模式、桥接模式、装饰器模式等
  • 行为型模式:策略模式、观察者模式、责任链模式等

2. 单例模式

单例模式是一种设计模式,它的核心是确保一个类只有一个实例存在。

单例模式的主要应用场景包括:

  1. 资源共享:例如数据库连接、文件系统等,只需要一个共享的资源控制实例。
  2. 全局状态管理:需要一个统一的地方来管理全局状态。

通过单例设计模式,可以避免多个对象创建导致的性能开销、防止多线程带来的多实例化问题,也可以针对一些敏感的资源做访问限制。

2.1 使用模块实现

最简单的方式就是通过模块实现单例模式的功能,因为从其它地方导入模块,这个模块肯定只有一个来源。

2.1.1 my_test.py

python">class Singleton:def __init__(self, name):self.name = namedef do(self):passa = Singleton("张三")

2.1.2 app.py

python">from my_test import a

2.2 使用装饰器实现

上述实现方法过于简单,没有什么含金量,一般面试的时候也肯定是想问如何用装饰器的方式来实现。因此,下面来看看装饰器是如何实现的,下述代码中:

  • singleton 是一个装饰器函数,它维护了一个字典 instances 来存储已经创建的类实例。
  • 当每次调用被装饰的类时,如果该类的实例还不存在,就创建一个新的实例并存储在 instances 中;如果已经存在,就直接返回已有的实例。

这样就保证了 MySingleton 类始终只有一个实例被创建和使用。

python">def singleton(cls):instances = {}    # 创建一个空字典def get_instance(*args, **kwargs):"""判断空字典中是否已经存在cls类:- 如果不存在,就新创建一个类对象,并存放到字典中- 如果存在,直接返回存在字典中的类对象"""if cls not in instances:instances[cls] = cls(*args, **kwargs)return instances[cls]return get_instance@singleton
class MySingleton:def __init__(self):self.data = "This is a singleton instance"instance1 = MySingleton()
instance2 = MySingleton()print(instance1 is instance2)  # True

2.3 使用 new 方法实现

另外,new 的实现方法也和装饰器有异曲同工之处,下述代码中:

  • 首先定义了一个类属性 _instance ,初始值为 None ,用于存储单例对象的引用。
  • new 是一个特殊的方法,用于控制对象的创建过程。而在 new 方法中,如果 _instance 为 None ,就通过 super().new(cls) 创建一个新的对象,并将其赋值给 _instance 。
  • 后续再次调用创建对象时,直接返回已经创建好的 _instance ,从而保证始终只有一个实例存在。
python">class Singleton:_instance = Nonedef __new__(cls, *args, **kwargs):if cls._instance is None:cls._instance = super().__new__(cls)return cls._instances1 = Singleton()
s2 = Singleton()print(s1 is s2)    # True

3. 工厂模式

工厂模式也是常用的设计模式之一,它是一种创建对象的设计模式。它的核心思想是将对象的创建与使用分离,通过一个工厂类来负责创建对象,即将实例化对象的过程封装起来,而客户端就不需要知道具体的创建细节。

工厂模式主要有三种形式:简单工厂模式、工厂方法模式和抽象工厂模式。

3.1 简单工厂模式

3.1.1 特点

  • 定义一个工厂类,具有一个创建对象的方法。
  • 根据传入的参数决定创建哪种具体的产品对象。

3.1.2 优缺点

  • 优点
    • 实现了对象创建和使用功能的分离,客户端不需要知道对象是如何创建的,只需要使用工厂提供的方法获取对象即可。
    • 集中了对象的创建逻辑,使得代码更具可读性和可维护性。
  • 缺点
    • 不符合开闭原则,即当需要添加新的产品时,需要修改工厂类的创建逻辑。
    • 工厂类的职责过重,可能会变得复杂和难以维护,如果产品种类过多,工厂类可能会变得庞大。

3.1.3 示例代码

假设我们有一个生产不同类型汽车的场景,有 “经济型轿车” 和 “豪华型轿车” 两种类型。在下述代码中:

  1. Car 是一个抽象的基类,EconomyCar 和 LuxuryCar 是具体的汽车类型,它们继承自 Car 类并实现了 drive 方法。
  2. CarFactory 是工厂类,它的 create_car 方法根据传入的参数创建相应类型的汽车对象。
python">from abc import ABC, abstractmethod# 抽象类
class Car(ABC):@abstractmethoddef drive(self):passclass EconomyCar(Car):def drive(self):print("Driving an economy car")class LuxuryCar(Car):def drive(self):print("Driving a luxury car")class CarFactory:def create_car(self, car_type):if car_type == 'economy':return EconomyCar()elif car_type == 'luxury':return LuxuryCar()# 客户端代码     
factory = CarFactory()economy_car = factory.create_car('economy')
economy_car.drive()luxury_car = factory.create_car('luxury')
luxury_car.drive()

Tips:抽象类
如果一个类继承自 ABC,且其中的方法加上了 @abstractmethod 的标签,那么这个类就是抽象类,它只能被其它类继承且其中的方法不能被实例化。

3.2 工厂方法模式

3.2.1 特点

  • 在工厂方法模式中,不再由一个单一的工厂类来创建所有的产品对象,而是为每种产品都提供一个具体的工厂类,这些工厂类都有一个共同的父类(抽象工厂类),其中定义了一个抽象的工厂方法。
  • 每个具体的工厂类负责创建一种特定类型的产品对象。

3.2.2 优点

  • 符合开闭原则:当需要添加新的产品时,不需要修改现有的工厂类,只需要添加一个新的具体工厂类和对应的产品类即可。
  • 解耦了产品的创建和使用:客户端只需要知道抽象工厂和抽象产品的接口,而不需要关心具体的产品创建细节。

3.2.3 示例代码

在下述示例中:

  1. Product 是抽象产品类,ConcreteProduct1 和 ConcreteProduct2 是具体的产品类。
  2. Factory 是抽象工厂类,定义了抽象的创建产品的方法 create_product 。
  3. ConcreteFactory1 和 ConcreteFactory2 是具体的工厂类,分别负责创建对应的具体产品。
python">from abc import ABC, abstractmethod# 抽象产品类
class Product(ABC):@abstractmethoddef show(self):pass# 具体产品类 1
class ConcreteProduct1(Product):def show(self):print("This is ConcreteProduct1")# 具体产品类 2
class ConcreteProduct2(Product):def show(self):print("This is ConcreteProduct2")# 抽象工厂类
class Factory(ABC):@abstractmethoddef create_product(self):pass# 具体工厂类 1
class ConcreteFactory1(Factory):def create_product(self):return ConcreteProduct1()# 具体工厂类 2
class ConcreteFactory2(Factory):def create_product(self):return ConcreteProduct2()# 客户端代码
factory1 = ConcreteFactory1()
product1 = factory1.create_product()
product1.show()factory2 = ConcreteFactory2()
product2 = factory2.create_product()
product2.show()

Tips:

  • ABC 是 Abstract Base Class 的缩写,用于定义抽象基类。
  • abstractmethod 装饰器用于将一个方法标记为抽象方法。抽象方法是没有实现的方法,子类必须实现这些抽象方法,否则子类也会被视为抽象类,无法实例化。

3.3 抽象工厂模式

3.3.1 特点

  • 抽象工厂定义了多个产品族的创建接口,每个产品族通常包含多个相关的产品对象。
  • 具体的工厂类实现抽象工厂的接口,负责创建属于特定产品族的产品对象。
  • 客户端通过抽象工厂的接口来获取产品族中的对象,而不关心具体的产品类和创建细节。

3.3.2 优点

  • 易于交换产品系列:当需要切换到不同的产品系列时,只需要更改使用的具体工厂类。
  • 有利于产品的一致性:确保属于同一个产品族的对象能够相互配合和协作。
  • 解耦了客户端与具体产品类的创建逻辑。

3.3.3 示例代码

在下述示例中:

  1. 我们定义了抽象产品 Chair 和 Table ,以及它们的具体实现 ModernChair、ModernTable、ClassicChair 和 ClassicTable 。
  2. FurnitureFactory 是抽象工厂,定义了创建椅子和桌子的抽象方法。
  3. ModernFurnitureFactory 和 ClassicFurnitureFactory 是具体的工厂,分别负责创建现代风格和古典风格的家具产品。
  4. 客户端可以根据需要选择不同的工厂来获取相应风格的家具产品。
python">from abc import ABC, abstractmethod# 抽象产品 - 椅子
class Chair(ABC):@abstractmethoddef sit(self):pass# 抽象产品 - 桌子
class Table(ABC):@abstractmethoddef put_stuff(self):pass# 具体产品 - 现代风格椅子
class ModernChair(Chair):def sit(self):print("Sitting on a modern chair")# 具体产品 - 现代风格桌子
class ModernTable(Table):def put_stuff(self):print("Putting stuff on a modern table")# 具体产品 - 古典风格椅子
class ClassicChair(Chair):def sit(self):print("Sitting on a classic chair")# 具体产品 - 古典风格桌子
class ClassicTable(Table):def put_stuff(self):print("Putting stuff on a classic table")# 抽象工厂
class FurnitureFactory(ABC):@abstractmethoddef create_chair(self):pass@abstractmethoddef create_table(self):pass# 具体工厂 - 现代风格家具工厂
class ModernFurnitureFactory(FurnitureFactory):def create_chair(self):return ModernChair()def create_table(self):return ModernTable()# 具体工厂 - 古典风格家具工厂
class ClassicFurnitureFactory(FurnitureFactory):def create_chair(self):return ClassicChair()def create_table(self):return ClassicTable()# 客户端代码
# 选择现代风格工厂
factory = ModernFurnitureFactory()
chair = factory.create_chair()
table = factory.create_table()chair.sit()
table.put_stuff()# 选择古典风格工厂
factory = ClassicFurnitureFactory()
chair = factory.create_chair()
table = factory.create_table()chair.sit()
table.put_stuff()

4. 责任链模式

4.1.1 特点
责任链模式(Chain of Responsibility Pattern)是一种行为设计模式,它允许多个对象都有机会处理请求,从而将请求的发送者和接收者解耦。

在责任链模式中,通常会创建一系列的处理对象(节点),每个对象都包含对下一个处理对象的引用,形成一个链。当有请求发送时,它会从链的头部开始依次传递,直到有一个处理对象能够处理该请求为止。

在这里插入图片描述

4.2 优点

  • 降低了发送者和接收者之间的耦合度,发送者不需要知道请求最终由谁处理。
  • 增强了系统的灵活性,可以动态地修改责任链的结构和节点的处理逻辑。
  • 实现了请求的发送者和处理者之间的职责分离。

4.3 示例代码

在下述示例中,创建了三个处理者 ConcreteHandler1、ConcreteHandler2 和 ConcreteHandler3,它们形成了一个责任链。根据请求的不同,由相应的处理者进行处理。

python">import abcclass Handler:def __init__(self, successor=None):self.successor = successor@abc.abstractmethoddef handle_request(self, request):pass  # 这个方法通常在具体的子类中实现,如果当前节点不能处理,则传递给下一个节点class ConcreteHandler1(Handler):def handle_request(self, request):if request < 10:print(f"ConcreteHandler1 处理了请求 {request}")elif self.successor:self.successor.handle_request(request)class ConcreteHandler2(Handler):def handle_request(self, request):if 10 <= request < 20:print(f"ConcreteHandler2 处理了请求 {request}")elif self.successor:self.successor.handle_request(request)class ConcreteHandler3(Handler):def handle_request(self, request):if request >= 20:print(f"ConcreteHandler3 处理了请求 {request}")else:print(f"没有合适的处理者来处理请求 {request}")# 创建责任链
handler1 = ConcreteHandler1()
handler2 = ConcreteHandler2()
handler3 = ConcreteHandler3()handler1.successor = handler2
handler2.successor = handler3# 发送请求
handler1.handle_request(5)      # ConcreteHandler1 处理了请求 5
handler1.handle_request(15)     # ConcreteHandler2 处理了请求 15
handler1.handle_request(25)     # ConcreteHandler3 处理了请求 25

http://www.ppmy.cn/devtools/151733.html

相关文章

Java List过滤 Stream API filter() 应用

Java 8 前用 for-each 循环或 Iterator 处理集合&#xff0c;引入 Stream API 后可更简洁、声明式地处理集合&#xff0c;在复杂数据处理时更便捷 1. Stream与Filter基础 Stream 是从支持数据源获取数据的序列&#xff0c;有强大 API 可执行中间和最终操作&#xff0c;能内部…

RPC 简介

RPC&#xff08;Remote Procedure Call&#xff0c;远程过程调用&#xff09;是一种通过网络请求执行远程服务器上的代码的技术&#xff0c;使得开发者可以调用远程系统中的函数&#xff0c;就像调用本地函数一样。它隐藏了底层网络通信的细节&#xff0c;简化了分布式系统的开…

C++学习记录

本文章建立在已学C语言的基础上 第一阶段 生成随机数函数&#xff1a;rand()。rand()%100指的是生成0~99的随机数。这样生成的随机数每次都是一样顺序出现的&#xff0c;为了防止这个问题出现&#xff0c;我们可以使用随机数种子&#xff0c;如下代码 #include<iostream&…

使用 Golang 编译 Linux 可运行文件

Golang&#xff08;或 Go&#xff09;是一种开源编程语言&#xff0c;因其简单、高效、并发编程支持而备受欢迎。本文将详细介绍如何使用 Golang 编译生成可以在 Linux 上运行的可执行文件。 一、安装 Golang 1.1 下载 Golang 从 Golang 官方网站下载适合你操作系统的安装包…

【STM32-学习笔记-7-】USART串口通信

文章目录 USART串口通信Ⅰ、硬件电路Ⅱ、常见的电平标准Ⅲ、串口参数及时序Ⅳ、STM32的USART简介数据帧起始位侦测数据采样波特率发生器 Ⅴ、USART函数介绍Ⅵ、USART_InitTypeDef结构体参数1、USART_BaudRate2、USART_WordLength3、USART_StopBits4、USART_Parity5、USART_Mode…

多态(4)

大家好&#xff0c;今天我们来讲讲向下转型这个知识点&#xff0c;这个知识点并没有向上转型用得那么频繁&#xff0c;但是也需要了解一下。 2.4.2向下转型 当一个子类对象经过向上转型之后当成父类方法使用,再无法调用子类的属性和方法。但有时候可能需要调用子类的属性和方…

PyTorch 中的 Dropout 解析

文章目录 一、Dropout 的核心作用数值示例&#xff1a;置零与缩放**训练阶段****推理阶段** 二、Dropout 的最佳使用位置与具体实例解析1. 放在全连接层后2. 卷积层后的使用考量3. BatchNorm 层与 Dropout 的关系4. Transformer 中的 Dropout 应用 三、如何确定 Dropout 的位置…

MinerU:高效智能PDF文档解析工具完全指南

引言 MinerU是一款开源的智能文档解析工具&#xff0c;专注于将PDF等文档高效转换为Markdown和JSON等结构化格式。在当前大语言模型(LLM)蓬勃发展的时代&#xff0c;高质量的结构化数据对于训练和微调LLM至关重要。MinerU通过其强大的智能文档解析能力&#xff0c;不仅可以为L…