Python中的设计模式与最佳实践【第166篇—设计模式】

👽发现宝藏

前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。【点击进入巨牛的人工智能学习网站】。

Python中的设计模式与最佳实践

在软件开发中,设计模式是一种解决常见问题的经过验证的解决方案。Python作为一种流行的编程语言,具有丰富的库和灵活的语法,使其成为实现设计模式的理想选择。本文将介绍几种常见的设计模式,并提供相应的Python示例代码,以便读者了解如何在Python中应用这些设计模式。

image-20240326010730581

1. 单例模式(Singleton Pattern)

单例模式确保一个类只有一个实例,并提供全局访问点。

class Singleton:_instance = Nonedef __new__(cls):if cls._instance is None:cls._instance = super().__new__(cls)return cls._instance# 示例
singleton1 = Singleton()
singleton2 = Singleton()print(singleton1 is singleton2)  # Output: True

2. 工厂模式(Factory Pattern)

工厂模式用于创建对象的接口,但允许子类决定实例化哪个类。它将实例化逻辑委托给子类。

from abc import ABC, abstractmethodclass Animal(ABC):@abstractmethoddef sound(self):passclass Dog(Animal):def sound(self):return "Woof!"class Cat(Animal):def sound(self):return "Meow!"class AnimalFactory:def get_animal(self, animal_type):if animal_type == "dog":return Dog()elif animal_type == "cat":return Cat()else:raise ValueError("Invalid animal type")# 示例
factory = AnimalFactory()
dog = factory.get_animal("dog")
cat = factory.get_animal("cat")print(dog.sound())  # Output: Woof!
print(cat.sound())  # Output: Meow!

3. 观察者模式(Observer Pattern)

观察者模式定义了对象之间的一对多依赖关系,使得当一个对象的状态发生变化时,其所有依赖项都会收到通知并自动更新。

class Observer:def update(self, message):passclass Subject:def __init__(self):self._observers = []def add_observer(self, observer):self._observers.append(observer)def remove_observer(self, observer):self._observers.remove(observer)def notify_observers(self, message):for observer in self._observers:observer.update(message)class MessagePublisher(Subject):def publish_message(self, message):self.notify_observers(message)class MessageSubscriber(Observer):def __init__(self, name):self.name = namedef update(self, message):print(f"{self.name} received message: {message}")# 示例
publisher = MessagePublisher()
subscriber1 = MessageSubscriber("Subscriber 1")
subscriber2 = MessageSubscriber("Subscriber 2")publisher.add_observer(subscriber1)
publisher.add_observer(subscriber2)publisher.publish_message("Hello, observers!")# Output:
# Subscriber 1 received message: Hello, observers!
# Subscriber 2 received message: Hello, observers!

4. 策略模式(Strategy Pattern)

策略模式定义了一系列算法,并将每个算法封装起来,使它们可以相互替换。该模式可以使算法的变化独立于使用它们的客户端。

from abc import ABC, abstractmethodclass Strategy(ABC):@abstractmethoddef execute(self, a, b):passclass AddStrategy(Strategy):def execute(self, a, b):return a + bclass SubtractStrategy(Strategy):def execute(self, a, b):return a - bclass Context:def __init__(self, strategy):self._strategy = strategydef execute_strategy(self, a, b):return self._strategy.execute(a, b)# 示例
add_strategy = AddStrategy()
subtract_strategy = SubtractStrategy()context = Context(add_strategy)
result1 = context.execute_strategy(5, 3)  # Output: 8context = Context(subtract_strategy)
result2 = context.execute_strategy(5, 3)  # Output: 2

5. 装饰器模式(Decorator Pattern)

装饰器模式允许向一个对象动态地添加新功能,同时不改变其结构。它是一种以透明、动态方式扩展对象的功能。

def make_bread(func):def wrapper():print("Mixing ingredients")func()print("Baking the bread")return wrapper@make_bread
def make_sandwich():print("Making sandwich")make_sandwich()# Output:
# Mixing ingredients
# Making sandwich
# Baking the bread

6. 原型模式(Prototype Pattern)

原型模式用于创建对象的一种模式,通过复制现有对象来创建新对象,从而避免了使用复杂的构造函数。

import copyclass Prototype:def __init__(self):self._objects = {}def register_object(self, name, obj):self._objects[name] = objdef unregister_object(self, name):del self._objects[name]def clone(self, name, **attrs):obj = copy.deepcopy(self._objects.get(name))obj.__dict__.update(attrs)return obj# 示例
class Car:def __init__(self):self.make = "Toyota"self.model = "Corolla"self.year = "2022"car_prototype = Car()
prototype = Prototype()
prototype.register_object("car", car_prototype)car = prototype.clone("car", year="2023")

这段代码展示了原型模式(Prototype Pattern)的实现。原型模式用于创建对象的一种模式,它允许通过复制现有对象来创建新对象,而不是通过实例化类来创建。让我们来解析一下:

  1. Prototype类:

    • __init__ 方法初始化一个空字典 _objects,用于存储注册的对象。
    • register_object 方法用于注册对象,将对象存储在 _objects 字典中,以便稍后克隆使用。
    • unregister_object 方法用于注销对象,从 _objects 字典中删除特定名称的对象。
    • clone 方法用于克隆对象。它接受一个名称参数,指定要克隆的对象的名称,并且可以接受额外的关键字参数来更新克隆对象的属性。它使用 copy.deepcopy 创建对象的深层副本,以避免对象间共享状态的问题。然后通过更新克隆对象的 __dict__ 属性来应用任何额外的属性更改,然后返回克隆后的对象。
  2. 示例类 Car:

    • 定义了一个简单的 Car 类,具有 make、model 和 year 属性。这是我们要克隆的对象的示例。
  3. 使用原型模式:

    • 创建了一个 Car 类的实例 car_prototype
    • 创建了一个 Prototype 实例 prototype
    • 使用 register_object 方法将 car_prototype 注册到原型中,名称为 “car”。
    • 使用 clone 方法从原型中克隆一个 Car 对象,名为 “car”,并且更新了 year 属性为 “2023”。

总之,这段代码演示了如何使用原型模式创建和管理对象的实例,以及如何在创建新对象时进行自定义属性更新。

image-20240326010909501

7. 建造者模式(Builder Pattern)

建造者模式用于创建复杂对象,它将对象的构建过程与其表示分离,从而可以按照不同的方式构建对象。

class Computer:def __init__(self, cpu, memory, storage):self.cpu = cpuself.memory = memoryself.storage = storageclass ComputerBuilder:def __init__(self):self._computer = Computer("", "", "")def set_cpu(self, cpu):self._computer.cpu = cpureturn selfdef set_memory(self, memory):self._computer.memory = memoryreturn selfdef set_storage(self, storage):self._computer.storage = storagereturn selfdef build(self):return self._computer# 示例
builder = ComputerBuilder()
computer = builder.set_cpu("Intel").set_memory("8GB").set_storage("256GB SSD").build()

8. 命令模式(Command Pattern)

命令模式将请求封装为对象,以便可以参数化其他对象对请求的执行、将请求排队或记录请求日志,以及支持可撤销的操作。

from abc import ABC, abstractmethodclass Command(ABC):@abstractmethoddef execute(self):passclass Light:def turn_on(self):print("Light is on")def turn_off(self):print("Light is off")class LightOnCommand(Command):def __init__(self, light):self._light = lightdef execute(self):self._light.turn_on()class LightOffCommand(Command):def __init__(self, light):self._light = lightdef execute(self):self._light.turn_off()class RemoteControl:def __init__(self):self._commands = {}def set_command(self, slot, command):self._commands[slot] = commanddef press_button(self, slot):if slot in self._commands:self._commands[slot].execute()# 示例
light = Light()
light_on = LightOnCommand(light)
light_off = LightOffCommand(light)remote = RemoteControl()
remote.set_command(1, light_on)
remote.set_command(2, light_off)remote.press_button(1)  # Output: Light is on
remote.press_button(2)  # Output: Light is off

这段代码展示了命令模式(Command Pattern)的实现,用于将请求封装成对象,从而使你能够参数化客户端对象以在不同的请求之间进行参数化。现在让我们来解析它:

  1. Command 类:

    • 是一个抽象基类 (Abstract Base Class, ABC),其中定义了一个抽象方法 execute(),它将在具体命令类中实现。所有具体命令类都必须实现这个方法。
  2. Light 类:

    • 定义了一种名为 Light 的简单设备,具有两种操作:turn_on()turn_off()
  3. 具体命令类 LightOnCommand 和 LightOffCommand:

    • 这两个类实现了 Command 类。它们分别将 Light 对象作为参数,在 execute() 方法中调用了 Light 对象的 turn_on()turn_off() 方法,实现了对 Light 设备的控制。
  4. RemoteControl 类:

    • 这是一个遥控器类,其中包含一个字典 _commands,用于存储命令对象。
    • set_command() 方法用于将命令对象与特定的槽位关联起来。
    • press_button() 方法用于按下特定槽位的按钮,如果有与该槽位关联的命令对象,则执行该命令。
  5. 示例:

    • 创建了一个 Light 对象。
    • 创建了两个具体命令对象,分别用于打开和关闭 Light。
    • 创建了一个 RemoteControl 对象,并将这两个具体命令对象分别与槽位 1 和槽位 2 关联。
    • 通过按下不同槽位的按钮来测试遥控器。按下槽位 1 会打印 “Light is on”,按下槽位 2 会打印 “Light is off”。

这段代码演示了如何使用命令模式来实现一个简单的遥控器系统,其中遥控器的按钮与具体的操作(命令)相关联,从而实现了解耦和可扩展性。

image-20240326011159505

9. 状态模式(State Pattern)

状态模式允许对象在其内部状态改变时改变其行为,使对象看起来好像修改了其类。

from abc import ABC, abstractmethodclass State(ABC):@abstractmethoddef handle(self):passclass StateContext:def __init__(self, state):self._state = statedef set_state(self, state):self._state = statedef request(self):self._state.handle()class ConcreteStateA(State):def handle(self):print("Handling request in State A")# State A transitions to State Bcontext.set_state(ConcreteStateB())class ConcreteStateB(State):def handle(self):print("Handling request in State B")# State B transitions to State Acontext.set_state(ConcreteStateA())# 示例
context = StateContext(ConcreteStateA())
context.request()  # Output: Handling request in State A
context.request()  # Output: Handling request in State B

10. 中介者模式(Mediator Pattern)

中介者模式用于减少对象之间的直接依赖关系,通过引入中介者对象来集中控制对象之间的交互。

class Mediator:def __init__(self):self._colleagues = []def add_colleague(self, colleague):self._colleagues.append(colleague)def send_message(self, message, colleague):for col in self._colleagues:if col != colleague:col.receive_message(message)class Colleague:def __init__(self, mediator):self._mediator = mediatordef send_message(self, message):self._mediator.send_message(message, self)def receive_message(self, message):print(f"Received message: {message}")# 示例
mediator = Mediator()
colleague1 = Colleague(mediator)
colleague2 = Colleague(mediator)mediator.add_colleague(colleague1)
mediator.add_colleague(colleague2)colleague1.send_message("Hello from colleague 1")
colleague2.send_message("Hi from colleague 2")# Output:
# Received message: Hello from colleague 1
# Received message: Hi from colleague 2

这段代码展示了中介者模式(Mediator Pattern)的实现,该模式用于减少对象之间的直接通信,而是通过一个中介对象来协调对象之间的交互。现在让我们解析代码:

  1. Mediator 类:

    • __init__ 方法初始化了一个空列表 _colleagues,用于存储参与通信的同事对象。
    • add_colleague 方法用于向中介者中添加同事对象。
    • send_message 方法用于发送消息给其他同事对象,它会遍历 _colleagues 列表,并调用每个同事对象的 receive_message 方法,除了消息的发送者自身。
  2. Colleague 类:

    • __init__ 方法接受一个中介者对象作为参数,并将其保存在 _mediator 属性中。
    • send_message 方法用于向中介者发送消息,它将消息和发送者自身作为参数传递给中介者的 send_message 方法。
    • receive_message 方法用于接收来自中介者的消息,并打印消息内容。
  3. 示例:

    • 创建了一个 Mediator 对象。
    • 创建了两个 Colleague 对象,并将它们注册到中介者中。
    • 同事对象通过调用自己的 send_message 方法来发送消息给其他同事对象,实际上是通过中介者来进行通信。
    • 两个同事对象收到了对方发送的消息,并打印出来。

通过中介者模式,对象之间的通信被解耦,每个对象只需与中介者对象通信,而不需要直接与其他对象通信,从而降低了对象之间的耦合度,提高了系统的可维护性和扩展性。

image-20240326011420376

适配器模式(Adapter Pattern)

适配器模式是一种结构型设计模式,用于将一个类的接口转换成客户端所期望的另一个接口。在软件开发中,经常会遇到需要使用已有的类,但是其接口与所需接口不匹配的情况。这时候就可以使用适配器模式来解决这一问题。

例如,假设有一个现有的类提供了特定功能,但是其方法命名或参数形式与新的需求不匹配。为了在不修改原有类的情况下与新的需求兼容,可以创建一个适配器类,该适配器类将新的需求接口转换为现有类的接口。

适配器模式通常包括三个角色:

  1. 目标接口(Target):客户端所期待的接口,适配器会实现这个接口。
  2. 适配者类(Adaptee):已经存在的类,其中包含客户端希望使用的功能,但其接口与目标接口不匹配。
  3. 适配器类(Adapter):通过实现目标接口并持有适配者对象,将客户端的请求转发给适配者对象。

适配器模式的优点包括:

  • 使得客户端能够使用已有的类,无需修改原有代码。
  • 提高代码的复用性和灵活性,适配器将现有类与新的需求解耦。

然而,适配器模式也有一些缺点:

  • 增加了系统的复杂性,引入了额外的类和对象。
  • 过多的适配器可能导致系统难以维护和理解。

在设计和应用适配器模式时,需要根据具体情况权衡利弊,确保使用适配器的同时保持代码的清晰和简洁。

外观模式(Facade Pattern)

外观模式是一种结构型设计模式,旨在为复杂系统提供一个简化的接口,以便客户端更容易地使用系统。在软件开发中,经常会遇到需要访问多个子系统或复杂接口的情况,这时候可以使用外观模式来隐藏系统的复杂性,提供一个统一的接口供客户端使用。

外观模式通常包括以下角色:

  1. 外观类(Facade):为客户端提供简单的接口,隐藏了子系统的复杂性,负责处理客户端的请求并将其委派给子系统处理。
  2. 子系统(Subsystem):包含多个相关的类或模块,负责实现系统的各种功能。

外观模式的优点包括:

  • 简化了客户端的调用过程,减少了客户端与子系统之间的耦合度。
  • 提高了代码的可维护性和可扩展性,客户端无需了解子系统的内部实现细节。

然而,外观模式也有一些缺点:

  • 过度使用外观模式可能导致系统的接口过于臃肿,难以维护。
  • 外观类成为了系统的唯一入口,一旦外观类出现问题,整个系统的功能都将受到影响。

在设计和应用外观模式时,需要根据系统的复杂性和需求来决定是否使用,以及如何设计外观类的接口,以确保系统的易用性和可维护性。

image-20240326011705094

总结

设计模式在软件开发中起着至关重要的作用,它们为开发人员提供了解决常见问题的有效工具和方法。本文介绍了两种常见的设计模式:适配器模式和外观模式。

适配器模式允许将一个类的接口转换成客户端所期望的另一个接口,从而使得原本不兼容的接口能够一起工作。通过适配器模式,我们可以在不修改原有类的情况下,使其与新的需求兼容,提高了代码的复用性和灵活性。

外观模式为复杂系统提供了一个简化的接口,隐藏了系统内部的复杂性,使客户端能够更轻松地使用系统。通过外观模式,我们可以将多个子系统或复杂接口封装起来,提供一个统一的接口给客户端,减少了客户端与子系统之间的耦合度,提高了代码的可维护性和可扩展性。

综上所述,设计模式是软件开发中不可或缺的一部分,它们为开发人员提供了解决问题的方法和思路,能够帮助我们编写更具有可读性、可维护性和可扩展性的代码。在实际项目中,根据具体需求和场景选择合适的设计模式,并结合最佳实践,将有助于开发出高质量的软件产品。

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

TCP网络程序

上一章我们基于UDP实现了几个网络程序,这一章我们开始使用TCP。 先简单复习一下TCP和UDP的特点: TCP特点 传输层协议有连接可靠传输面向字节流 UDP特点 传输层协议无连接不可靠传输面向数据报 可以看到TCP是有链接的,而UDP是无连接的&#…

最优算法100例之51-链表的第一个公共结点

专栏主页:计算机专业基础知识总结(适用于期末复习考研刷题求职面试)系列文章https://blog.csdn.net/seeker1994/category_12585732.html 题目描述 寻找6 题解报告 思路: (1)使用栈,依次将两个链表入栈,然后出栈&#x

十大排序——7.希尔排序

下面我们来看一下希尔排序 目录 1.介绍 2.代码实现 3.总结与思考 1.介绍 希尔排序是插入排序的一种优化,可以理解为是一种分组的插入排序。 希尔排序的要点: 简单来说,就是分组实现插入,每组元素的间隙称为gap,…

【核心完整复现】基于目标级联法的微网群多主体分布式优化调度

1 主要内容 之前发布了华电学报的复现程序《基于目标级联法的微网群多主体分布式优化调度》,具体链接为【防骗版】基于目标级联法的微网群多主体分布式优化调度,虽然对模型及结果进行了复现,但是部分模型细节和参数并没有完全实现&#xff0…

微服务之网关路由

一、概述 1.1认识网关 什么是网关? 顾明思议,网关就是网络的关口。数据在网络间传输,从一个网络传输到另一网络时就需要经过网关来做数据的路由和转发以及数据安全的校验。 更通俗的来讲,网关就像是以前园区传达室的大爷。 外…

2024中国内燃机展-北京汽车发动机零部件展

2024第二十三届中国国际内燃机与零部件展览会 由中国内燃机工业协会主办、中国机床专用技术设备有限公司、汽车工艺装备成套开发集团协办的2024中国国际内燃机及动力装备博览会(简称“动博会”)将于2024年10月11日-13日在亦创国际会展中心隆重举办。本届…

OpenHarmony开发案例:【分布式遥控器】

1.概述 目前家庭电视机主要通过其自带的遥控器进行操控,实现的功能较为单一。例如,当我们要在TV端搜索节目时,电视机在遥控器的操控下往往只能完成一些字母或数字的输入,而无法输入其他复杂的内容。分布式遥控器将手机的输入能力…

Backend - Django Swagger

目录 一、安装依赖 二、配置环境 三、路由(urls) 四、swagger UI 界面 (一)UI 界面 (二)单引号问题:Expecting property name enclosed in double quotes 1. 原因 2. 解决 五、自定义s…

Day 27 39. 组合总和 40.组合总和II 131.分割回文串

组合总和 给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。 candidates 中的数字可以无限制重复被选取。 说明: 所有数字(包括 target)都是正整数。解集不能…

CentOS下gitlab迁移和升级_gitlab备份的可以通用centos和 ubuntu吗(1)

先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7 深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞…

IAM 统一身份认证与访问管理服务

即统一身份认证与访问管理服务,是云服务商提供的一套云上身份管理解决方案,可帮助企业安全地管理云上资源的访问权限。 在当今云计算时代,企业越来越依赖云服务来存储和处理敏感数据。然而,这也带来了新的安全挑战,即…

牛客2024 【牛客赛文X】春招冲刺 ONT84 子数组的最小值之和【中等 单调栈 Java、Go、PHP】

题目 题目链接: https://www.nowcoder.com/practice/a7401d0dd4ec4071a31fd434e150bcc2 思路 单调栈解决的问题单调栈解决的问题是在一个数组中想知道所有数中, 左边离他近的比他大的和右边离他近的比他大的数 思考的问题:如果知道所有数上…