[Python进阶] 类的设计模式
4.11 设计模式
在Python中,类的设计模式是指一种通用的解决方案或设计模板,针对特定的问题或需求构建类结构,并提供相关的方法和属性。这些设计模式可以帮助开发人员遵循最佳实践、提高代码质量、增强可读性、降低维护成本。
需要注意的是,类设计模式不是语言特定的,这些模式同样适用于其他面向对象编程语言。
在 Python 中,有多种常见的类设计模式。下面将进行介绍。
4.11.1 工厂模式(Factory Pattern)
用于创建对象实例的模式,简化了对象的创建过程。
在Python中,类设计的工厂模式是一种创建对象的方法。它可以使用一个公共接口来创建不同的对象,这些对象通常共享相同的属性和行为。更具体地说,工厂模式可以通过使用过程化编程技术和面向对象编程技术来实现。
下面是一个示例:
class Dog:def __init__(self, name):self._name = namedef speak(self):return "Woof!"class Cat:def __init__(self, name):self._name = namedef speak(self):return "Meow!"def get_pet(pet="dog"):pets = dict(dog=Dog("Hope"), cat=Cat("Peace"))return pets[pet]dog = get_pet("dog")
print(dog.speak())cat = get_pet("cat")
print(cat.speak())
在上述代码中,我们定义了两个类:Dog和Cat,每个类都有它自己的__init__函数和speak方法。然后我们定义了一个get_pet函数,该函数接收一个参数pet并根据传递的值获取pets字典中对应的实例赋值给dog或者cat变量中。
如果传入的pet参数是"dog",那么将调用get_pet函数,并返回一个Dog对象;而如果传入的参数是"cat",那么会返回一个Cat对象。最后我们分别调用了dog.speak()和cat.speak()方法输出其对应的声音。
这种设计模式对于以下情况非常有用:
- 当我们需要隐藏对象创建的实现细节时。
- 当我们希望将对象的创建与使用分开时。
- 当我们想要通过公共接口在运行时确定对象类型时。
4.11.2 单例模式(Singleton Pattern)
确保类只能有一个实例,并提供对该实例的全局访问点。
在Python中,类设计的单例模式是指一个类只有一个实例对象。这意味着无论如何调用该类,在内存中只会存在同一个实例对象,如果再次创建该类的实例对象时,将返回已经存在的那个。这可以避免在程序中多次创建相同的对象,节省资源和提高性能。
下面是一个示例:
class Singleton:__instance = Nonedef __new__(cls, name):if cls.__instance is None:cls.__instance = super().__new__(cls)cls.__instance.__initialized = Falsereturn cls.__instancedef __init__(self, name):if not self.__initialized:self.name = nameself.__initialized = Truedef say_hello(self):print(f"Hello, I am {self.name} ({id(self)})!")
在上述代码中,我们定义了一个名为Singleton
的类,使用了双重判断的方式确保仅创建一个实例对象。在类的__new__
方法中,如果没有创建过实例对象,就通过super()
调用父类的__new__
方法来创建一个实例对象,并将它赋值给__instance
属性。若已经创建过实例对象,则直接返回现有的那个实例对象。同时类中的__initialized
属性用于确保__init__
方法只执行一次。
我们还在类的__init__
方法中添加了一个名为name
的属性,以标识该实例的名称。最后我们定义了一个say_hello
方法,用于输出实例的名称和其在内存中的地址。
下面展示如何使用Singleton
类:
dog1 = Singleton("Hope")
dog2 = Singleton("Peace")print(id(dog1))
print(id(dog2))dog1.say_hello()
dog2.say_hello()print(dog1 == dog2)
在上述代码中,我们先创建了两个实例对象dog1
和dog2
,采用不同的name,但是由于是单例模式,只有第一次的name能够正常赋值,dog2的name则无法再次赋值。最后得到的结果就显示dog1和dog2的id一致,say_hello函数返回的也一致。
4.11.3 观察者模式(Observer Pattern)
在对象之间建立一对多的依赖关系,以便当一个对象状态更改时通知其所有依赖项。
在Python中,类设计的观察者模式是指当一个对象的状态发生改变时,所有依赖它的其他对象都会得到通知并自动更新。
下面是一个示例:
class Observer:def update(self, obj, *args, **kwargs):passclass Observable:def __init__(self):self._observers = []def addObserver(self, observer):if observer not in self._observers:self._observers.append(observer)def removeObserver(self, observer):if observer in self._observers:self._observers.remove(observer)def notifyObservers(self, obj, *args, **kwargs):for observer in self._observers:observer.update(obj, *args, **kwargs)class Dog(Observable):def __init__(self, name="dog"):super().__init__()self._name = namedef setName(self, name):self._name = nameself.notifyObservers(self)def getName(self):return self._nameclass Owner(Observer):def __init__(self, name):self._name = namedef update(self, dog, *args, **kwargs):print(f"{self._name}: {dog.getName()} seems happy today!")dog1 = Dog("Hope")
dog2 = Dog("Peace")
owner1 = Owner("Alice")
owner2 = Owner("Bob")dog1.addObserver(owner1)
dog1.addObserver(owner2)
dog2.addObserver(owner2)dog1.setName("Happy Hope")
dog2.setName("Peaceful Peace")
在上面的代码中,我们定义了两个类Observer
和Observable
,以及继承自Observable
的Dog
类和继承自Observer
的Owner
类。
Observer
类中定义了名称为update
的方法,这是观察者需要实现的方法。在本例中,我们没有在其中写入任何代码。 Observable
类实现了添加、删除和通知观察者对象的方法,其中addObserver
将要添加的观察者放入到观察者列表中。此时观察者可以根据removeObserver
则是从观察者列表中剔除。notifyObservers
则是通知观察者。
4.11.4 适配器模式(Adapter Pattern)
将接口转换为其他接口,以兼容客户端代码的需求。
适配器模式是一种设计模式,它允许我们将一个类的接口转换为另一个客户端所期望的接口。在Python中,适配器模式的实现方式通常涉及到继承和组合两种方式。
下面是一个使用继承实现适配器模式的示例,假设我们有两个类,一个是Adaptee类,具有不同于目标客户端所期望的接口:
class Adaptee:def specific_request(self):return "adaptee code"
和一个客户端所期望的接口Target:
class Target:def request(self):pass
我们可以通过TargetClassAdapter类来使Adaptee与Target兼容,适配器将Adaptee的方法调用转换成Target客户端所期望的接口:
class TargetClassAdapter(Target, Adaptee):def request(self):return self.specific_request()
这样一来,客户端就可以使用TargetClassAdapter类来调用Adatpee的方法,同时符合Target接口规范:
if __name__ == "__main__":target = TargetClassAdapter()result = target.request()print(result) # 'adaptee code'
同样,我们也可以使用组合方式来实现适配器模式。
4.11.5 组合模式(Composite Pattern)
通过将对象组合成树形结构,使得单个对象和组合对象都可以按统一的方式进行处理。
在Python中,组合模式指的是将对象组合成树形结构以表示“部分-整体”的层次结构。组合能让客户端以一致的方式处理个别对象以及对象组合。
以下是使用Python实现组合模式的简单示例:
class Component:def __init__(self, name):self.name = namedef add(self, component):passdef remove(self, component):passdef display(self, depth):passclass Leaf(Component):def add(self, component):print("Cannot add to a leaf")def remove(self, component):print("Cannot remove from a leaf")def display(self, depth):print("-" * depth + self.name)class Composite(Component):def __init__(self, name):super().__init__(name)self.children = []def add(self, component):self.children.append(component)def remove(self, component):self.children.remove(component)def display(self, depth):print("-" * depth + self.name)for child in self.children:child.display(depth + 2)if __name__ == "__main__":root = Composite("root")root.add(Leaf("leaf A"))root.add(Leaf("leaf B"))comp = Composite("Composite X")comp.add(Leaf("leaf XA"))comp.add(Leaf("leaf XB"))root.add(comp)root.display(1)
在这个例子中,Component
类代表组合模式中的组件,其中包含了添加、删除和显示其内容的方法。Leaf
类代表叶节点,不能够包含其他的组件。Composite
类代表组合节点,包含了多个子组件。
在这个示例中,创建了一个root
组合节点,包含两个叶节点Leaf A
和Leaf B
以及一个名为Composite X
的子组合节点。调用display()
方法时,将按树形结构递归地显示所有组件的内容。
4.11.6 策略模式(Strategy Pattern)
定义算法族,使它们之间可以互相替换,而不会影响到客户端的使用。
类的策略模式是一种设计模式,它允许在运行时选择算法的不同变体或行为。这个模式中,我们将不同的算法或策略封装成不同的类并让他们可以相互替换。
以下是一个简单的代码示例:
class Strategy:def do_algorithm(self, data):passclass ConcreteStrategyA(Strategy):def do_algorithm(self, data):return sorted(data)class ConcreteStrategyB(Strategy):def do_algorithm(self, data):return list(reversed(sorted(data)))class Context:def __init__(self, strategy: Strategy):self._strategy = strategydef execute_strategy(self, data):return self._strategy.do_algorithm(data)if __name__ == "__main__":context_a = Context(ConcreteStrategyA())result_a = context_a.execute_strategy([1, 3, 2])print(result_a)context_b = Context(ConcreteStrategyB())result_b = context_b.execute_strategy([1, 3, 2])print(result_b)
在这个例子中,我们定义了一个Strategy
的基类和两个具体的策略类:ConcreteStrategyA
和ConcreteStrategyB
。每个策略类都实现了do_algorithm
方法,并分别提供了不同的实现。
接着我们定义了一个上下文类Context
用来执行策略并生成所需的结果。这个类包含一个指向Strategy
对象的引用,并在执行方法时将数据传递给所选的策略类进行处理。
最后我们可以创建不同的上下文对象,并通过方法的多态性执行相应的策略。这样就可以实现运行时动态选择算法行为的目的。
4.11.7 装饰器模式(Decorator Pattern)
动态地向对象添加额外的行为,而无需修改原始类的代码。
在Python中,类设计的装饰器模式是指,使用装饰器来修改一个类的行为或属性,而不必直接修改该类的原始定义。这可以使代码更加灵活和可维护。
以下是一个实例,其中定义了一个名为Logger
的装饰器,它可以添加记录方法到一个类中:
def Logger(cls):"""A decorator that adds logging functionality to a class"""# Define the logging methoddef log(self, message):print(f"{self.__class__.__name__}: {message}")# Add the logging method to the classcls.log = log# Return the modified classreturn cls# Define a class with the Logger decorator
@Logger
class MyClass:pass# Use the class and its logging method
my_object = MyClass()
my_object.log("Hello World!")
在上面的示例中,Logger
函数作为一个装饰器来使用,用于增加Python类的日志功能。当我们在类定义之前应用此装饰器时,Logger
函数将自动被调用并向该类添加log
方法,这个方法可以访问该类的名称和任何传递给它的消息。因此,在创建MyClass
对象后,我们可以调用该对象的log
方法,并输出一条带有类的名称和消息的日志信息。
4.11.8 建造者模式(Builder Pattern)
将复杂的对象构建与其表示分离,以便不同的表示方式可以用于该对象进行构建。
类设计的建造者模式是一种创建复杂对象的设计模式,它使用多个简单的对象逐步构建出一个复杂的对象。这种模式是将一个复杂对象的构建与其表示分离,使得同样的构建过程可以创建不同的表示。
在Python中,可以用下面的示例演示建造者模式。
class Pizza:def __init__(self, dough='', sauce='', toppings=[]):self.dough = doughself.sauce = sauceself.toppings = toppingsdef __str__(self):return 'dough: {}, sauce: {}, toppings: {}'.format(self.dough, self.sauce, ', '.join(self.toppings))class PizzaBuilder:def __init__(self):self.pizza = Pizza()def set_dough(self, dough):self.pizza.dough = doughreturn selfdef set_sauce(self, sauce):self.pizza.sauce = saucereturn selfdef add_topping(self, topping):self.pizza.toppings.append(topping)return selfdef build(self):return self.pizzaclass MargheritaPizzaBuilder(PizzaBuilder):def __init__(self):super().__init__()self.pizza.dough = 'thin'self.pizza.sauce = 'tomato'def add_toppings(self):self.pizza.toppings.extend(['mozzarella', 'basil'])return selfclass PepperoniPizzaBuilder(PizzaBuilder):def __init__(self):super().__init__()self.pizza.dough = 'pan'self.pizza.sauce = 'tomato'def add_toppings(self):self.pizza.toppings.extend(['mozzarella', 'pepperoni'])return selfclass Director:def __init__(self, builder=None):self.builder = builderdef set_builder(self, builder):self.builder = builderdef construct_pizza(self):if not self.builder:raise ValueError("Builder is not set")self.builder.add_topping().build()
在这个例子中,PizzaBuilder类可以创建定制并返回Pizza。MargheritaPizzaBuilder、PepperoniPizzaBuilder则创建特定的Pizza。Director类则可以通过传入不同的PizzaBuilder构建出不同的Pizza。使得同样的构建过程创建出不同的Pizza。
相关文章:
[Python进阶] 类的设计模式
4.11 设计模式 在Python中,类的设计模式是指一种通用的解决方案或设计模板,针对特定的问题或需求构建类结构,并提供相关的方法和属性。这些设计模式可以帮助开发人员遵循最佳实践、提高代码质量、增强可读性、降低维护成本。 需要注意的是&a…...
设计模式 07 桥接模式
桥接模式(Bridge Pattern)属于结构型模式 概述 桥接模式是将抽象部分与它的实现部分分离,使它们都可以独立地变化。它是一种对象结构型模式,又称为柄体(Handle and Body)模式或接口(Interface&…...

linux系统(centos、ubuntu、银河麒麟服务、uos、deepin)判断程序是否已安装,通用判断方法:使用所有应用和命令的判断
前言 项目中需要判断linux服务器中是否已经安装了某个服务 方法有很多种,但是很多都不通用, 脚本代码就不容易做成统一的 解决方案 用下面的脚本代码去进行判断 用jdk测试 脚本意思如下: 输入java -version命令,将返回的字…...
机器学习各算法优缺点汇总
链接: (链接: link)...

手把手教你部署Jenkins教程,小白也能学会(多图预警)!
背景 公司的前端、后端构建及部署工作都是人工去做,随着业务扩大,项目迭代速度变快,人员增多,各种问题都暴露出来,将通过一个简单案例分享一下基于Jenkins的前后端自动化工作流搭建的过程,搭建完这套工作流…...

一种IDEA疑难杂症的解决办法
解决办法 重启IDEA 针对于IDEA各种羡慕解析,运行时问题,但是无法通过搜索引擎得到答案的问题请试试此方法。 删除根目录下[.idea]文件夹后重启 此文件夹为idea首次导入项目时根据项目情况自动生成的配置文件。方便idea下次更快的解析项目。但是某些情…...

TikTok小店玩法有哪些?一起来玩转TiKTok!
随着TikTok在海外市场份额不断增加,越来越多卖家选择入驻TikTok跨境小店,但是在入驻之后我们需要知道有哪些主流玩法,才能根据实际情况制定合适的运营方案。接下来小编就给大家介绍一下TikTok小店玩法有哪些! 本土模式 这种模式…...
Mongodb 集合插入文档自动生成ObjectId
插入单个文档 Mongodb 使用以下几种方法来插入文档 , Mongodb V5.0 使用 mongosh 客户端: 插入单个文档 db.collection.insertOne() 将单个 文档插入到集合中。 如果该集合当前不存在,则插入操作将创建该集合。 如果文档未指定_id字段&am…...

C# .aspx网页获取RFID读卡器HTTP协议提交的访问文件Request获得卡号、机号,Response回应驱动读卡器显示响声
本示例使用的设备:RFID网络WIFI无线TCP/UDP/HTTP可编程二次开发读卡器POE供电语音-淘宝网 (taobao.com) 服务端代码: using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.UI; using System.Web.…...

Kali Linux 2023.3 发布
Offective Security 发布了 Kali Linux 2023.3,这是其渗透测试和数字取证平台的最新版本。 Kali Linux 2023.3 中的新工具 除了对当前工具的更新之外,新版本的 Kali 通常还会引入新的工具。 这次,他们是: Calico – 云原生网络…...
如何用Python实现从pdf文件精准抓取数据生成数据库!
要从PDF文件中提取数据并生成数据库,你可以使用Python中的一些库和工具来实现。 1、安装必要的库:确保已安装所需的库。除了之前提到的PyPDF2、pdfminer.six和pdftotext之外,你可能还需要其他的库来处理提取的数据和数据库操作。例如&#x…...

科技资讯|苹果Apple Watch新专利,可根据服装、表带更换表盘颜色
根据美国商标和专利局(USPTO)公示的清单,苹果公司近日获得了一项 Apple Watch 相关的技术专利,最大的亮点在于配备颜色采样传感器,可以根据表带、服装自动变幻变盘颜色和主题。 Apple Watch 正面配备颜色采样传感器&am…...

猜数游戏-Rust版
cargo new guessing_game 创建项目 输入任意内容,并打印出来 main.rs: use std::io; // 像String这些类型都在预先导入的prelude里,如果要使用的不在prelude里,则需要显式导入fn main() { println!("猜数"); println!("…...

从零起步:学习数据结构的完整路径
文章目录 1. 基础概念和前置知识2. 线性数据结构3. 栈和队列4. 树结构5. 图结构6. 散列表和哈希表7. 高级数据结构8. 复杂性分析和算法设计9. 实践和项目10. 继续学习和深入11. 学习资源12. 练习和实践 🎉欢迎来到数据结构学习专栏~从零起步:学习数据结构…...
如何在浏览器中启用 WebGL 以使用 HTML5 3D 查看器
描述 WebCenter 中的 HTML5 3D Collada Viewer(自 14.1 以来新增)要求在浏览器中启用 WebGL。较旧的浏览器可能不支持此功能,或者要求用户首先显式启用此功能。本页介绍如何为所有主要浏览器启用此功能。WebGL 3D 查看器 本文是以下超级用户…...

【计算机协议】第一章——HTTP协议详解
前言 HTTP(Hypertext Transfer Protocol)即超文本传输协议,是一种用于传输超媒体文档(例如HTML)的应用层协议。HTTP协议采用C/S(客户端/服务器)模式,客户端发起请求,服务…...

【FAQ】安防监控视频汇聚平台EasyCVR接入GB国标设备,无法显示通道信息的排查方法
安防视频监控/视频集中存储/云存储/磁盘阵列EasyCVR平台可拓展性强、视频能力灵活、部署轻快,可支持的主流标准协议有国标GB28181、RTSP/Onvif、RTMP等,以及支持厂家私有协议与SDK接入,包括海康Ehome、海大宇等设备的SDK等。平台既具备传统安…...
Matlab 生成一定信噪比的信号
文章目录 【 1. 信噪比 】【 2. 功率归一化 】2.1 实信号实噪声2.2 实信号复噪声 【 3. 能量归一化 】3.1 实信号实噪声3.2 实信号复噪声 【 4. 小结 】 【 1. 信噪比 】 信噪比公式 1 : S N R 10 ∗ l o g 10 P s P n 信噪比公式1:SNR10*log_{10}\frac…...
[国产MCU]-W801开发实例-定时器
定时器 文章目录 定时器1、定时器介绍2、定时器驱动API3、定时器使用示例本文将详细介绍如何使用W801的定时器模块。 1、定时器介绍 W801的定时器包含一个32-bit自动加载的计数器,该计数器由系统时钟经过分频后驱动。 W801有 6路完全独立定时器。实现了精确的定时时间以及中断…...
基于 CentOS 7 构建 LVS-DR 群集,配置nginx负载均衡。
基于 CentOS 7 构建 LVS-DR 群集。 关闭防火墙 [rootlocalhost ~]# systemctl stop firewalld 安装ifconfig yum install net-tools.x86_64 -y 准备四台虚拟机 IP 用途 19.168.244.144 客户端 192.168.244.145 lvs 192.168.244.148 RS 192.168.244.149 RS 在DS上 …...

华为云AI开发平台ModelArts
华为云ModelArts:重塑AI开发流程的“智能引擎”与“创新加速器”! 在人工智能浪潮席卷全球的2025年,企业拥抱AI的意愿空前高涨,但技术门槛高、流程复杂、资源投入巨大的现实,却让许多创新构想止步于实验室。数据科学家…...
[2025CVPR]DeepVideo-R1:基于难度感知回归GRPO的视频强化微调框架详解
突破视频大语言模型推理瓶颈,在多个视频基准上实现SOTA性能 一、核心问题与创新亮点 1.1 GRPO在视频任务中的两大挑战 安全措施依赖问题 GRPO使用min和clip函数限制策略更新幅度,导致: 梯度抑制:当新旧策略差异过大时梯度消失收敛困难:策略无法充分优化# 传统GRPO的梯…...
Ubuntu系统下交叉编译openssl
一、参考资料 OpenSSL&&libcurl库的交叉编译 - hesetone - 博客园 二、准备工作 1. 编译环境 宿主机:Ubuntu 20.04.6 LTSHost:ARM32位交叉编译器:arm-linux-gnueabihf-gcc-11.1.0 2. 设置交叉编译工具链 在交叉编译之前&#x…...
脑机新手指南(八):OpenBCI_GUI:从环境搭建到数据可视化(下)
一、数据处理与分析实战 (一)实时滤波与参数调整 基础滤波操作 60Hz 工频滤波:勾选界面右侧 “60Hz” 复选框,可有效抑制电网干扰(适用于北美地区,欧洲用户可调整为 50Hz)。 平滑处理&…...

基于uniapp+WebSocket实现聊天对话、消息监听、消息推送、聊天室等功能,多端兼容
基于 UniApp + WebSocket实现多端兼容的实时通讯系统,涵盖WebSocket连接建立、消息收发机制、多端兼容性配置、消息实时监听等功能,适配微信小程序、H5、Android、iOS等终端 目录 技术选型分析WebSocket协议优势UniApp跨平台特性WebSocket 基础实现连接管理消息收发连接…...

【网络安全产品大调研系列】2. 体验漏洞扫描
前言 2023 年漏洞扫描服务市场规模预计为 3.06(十亿美元)。漏洞扫描服务市场行业预计将从 2024 年的 3.48(十亿美元)增长到 2032 年的 9.54(十亿美元)。预测期内漏洞扫描服务市场 CAGR(增长率&…...

华为OD机试-食堂供餐-二分法
import java.util.Arrays; import java.util.Scanner;public class DemoTest3 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseint a in.nextIn…...
鱼香ros docker配置镜像报错:https://registry-1.docker.io/v2/
使用鱼香ros一件安装docker时的https://registry-1.docker.io/v2/问题 一键安装指令 wget http://fishros.com/install -O fishros && . fishros出现问题:docker pull 失败 网络不同,需要使用镜像源 按照如下步骤操作 sudo vi /etc/docker/dae…...

如何在最短时间内提升打ctf(web)的水平?
刚刚刷完2遍 bugku 的 web 题,前来答题。 每个人对刷题理解是不同,有的人是看了writeup就等于刷了,有的人是收藏了writeup就等于刷了,有的人是跟着writeup做了一遍就等于刷了,还有的人是独立思考做了一遍就等于刷了。…...
JavaScript 数据类型详解
JavaScript 数据类型详解 JavaScript 数据类型分为 原始类型(Primitive) 和 对象类型(Object) 两大类,共 8 种(ES11): 一、原始类型(7种) 1. undefined 定…...