网站首页 > 技术文章 正文
点赞、收藏、加关注,下次找我不迷路
刚学 Python ,是不是一听到 "设计模式" 就头大?觉得这是大佬才需要掌握的高深知识?别害怕!今天咱们就用通俗易懂的语言,把 Python 开发中最常用的 3 个设计模式 —— 工厂模式、单例模式、适配器模式,讲明白!学会它们,你的代码不仅会更规范、更灵活,还能直接提升一个档次,离成为高薪 Python 开发工程师又近了一步!
一、工厂模式:对象的 "智能工厂",让创建对象更简单
1. 什么是工厂模式?
咱们先打个比方,假如你开了一家奶茶店,顾客可能会点珍珠奶茶、草莓奶昔、芒果冰沙等不同的饮品。如果每次顾客点单,你都要亲自去准备材料、制作饮品,那效率可太低了。而且如果将来要新增一种饮品,比如杨枝甘露,你又得重新修改制作流程,非常麻烦。
工厂模式就相当于开了一个 "饮品制造工厂",你只需要告诉工厂你想要什么饮品,工厂就会按照既定的流程帮你生产出来。你不用关心具体的制作细节,只需要和工厂打交道就行。在编程中,工厂模式就是用来创建对象的一种模式,它把对象的创建和使用分离开来,让代码更灵活、更易于维护。
2. 工厂模式的三种类型
工厂模式主要有三种类型:简单工厂模式、工厂方法模式和抽象工厂模式。咱们一个个来看看,为了方便理解,还是用奶茶店的例子来讲解。
(1)简单工厂模式
简单工厂模式是最简单的工厂模式,它有一个专门的工厂类,负责创建不同的产品对象。就像咱们的奶茶店,有一个总的饮品工厂,当顾客点单时,工厂根据订单类型生产对应的饮品。
代码示例:
class MilkTea:
def drink(self):
print("喝珍珠奶茶")
class StrawberryShake:
def drink(self):
print("喝草莓奶昔")
class MangoSmoothie:
def drink(self):
print("喝芒果冰沙")
class DrinkFactory:
@staticmethod
def create_drink(drink_type):
if drink_type == "milk_tea":
return MilkTea()
elif drink_type == "strawberry_shake":
return StrawberryShake()
elif drink_type == "mango_smoothie":
return MangoSmoothie()
else:
raise ValueError("不支持的饮品类型")
# 使用工厂创建饮品
drink1 = DrinkFactory.create_drink("milk_tea")
drink1.drink() # 输出:喝珍珠奶茶
drink2 = DrinkFactory.create_drink("strawberry_shake")
drink2.drink() # 输出:喝草莓奶昔
优点:简单易用,客户端不需要知道具体的产品类,只需要知道产品类型即可创建对象。
缺点:工厂类承担了所有产品的创建逻辑,如果产品类型过多,工厂类会变得很臃肿,而且新增产品时需要修改工厂类的代码,违反了 "开闭原则"(对扩展开放,对修改关闭)。
(2)工厂方法模式
为了解决简单工厂模式的缺点,工厂方法模式把工厂类也进行了抽象,定义了一个抽象工厂类,具体的工厂类负责创建具体的产品类。比如咱们的奶茶店,不同的饮品可以有不同的工厂,比如珍珠奶茶工厂、草莓奶昔工厂等,每个工厂专门生产一种饮品。
代码示例:
from abc import ABC, abstractmethod
class Drink(ABC):
@abstractmethod
def drink(self):
pass
class MilkTea(Drink):
def drink(self):
print("喝珍珠奶茶")
class StrawberryShake(Drink):
def drink(self):
print("喝草莓奶昔")
class DrinkFactory(ABC):
@abstractmethod
def create_drink(self):
pass
class MilkTeaFactory(DrinkFactory):
def create_drink(self):
return MilkTea()
class StrawberryShakeFactory(DrinkFactory):
def create_drink(self):
return StrawberryShake()
# 使用具体工厂创建饮品
factory1 = MilkTeaFactory()
drink1 = factory1.create_drink()
drink1.drink() # 输出:喝珍珠奶茶
factory2 = StrawberryShakeFactory()
drink2 = factory2.create_drink()
drink2.drink() # 输出:喝草莓奶昔
优点:符合 "开闭原则",新增产品时只需要新增对应的产品类和工厂类,不需要修改现有代码。
缺点:当产品类型较多时,需要创建大量的工厂类,增加了代码的复杂度。
(3)抽象工厂模式
抽象工厂模式是工厂方法模式的升级,它可以创建一系列相关或相互依赖的产品对象。比如咱们的奶茶店,不仅要生产饮品,还要生产对应的杯子、吸管等配件,抽象工厂模式就可以同时创建饮品和配件。
代码示例:
from abc import ABC, abstractmethod
class Drink(ABC):
@abstractmethod
def drink(self):
pass
class MilkTea(Drink):
def drink(self):
print("喝珍珠奶茶")
class StrawberryShake(Drink):
def drink(self):
print("喝草莓奶昔")
class Cup(ABC):
@abstractmethod
def use(self):
pass
class SmallCup(Cup):
def use(self):
print("使用小杯子")
class LargeCup(Cup):
def use(self):
print("使用大杯子")
class AbstractFactory(ABC):
@abstractmethod
def create_drink(self):
pass
@abstractmethod
def create_cup(self):
pass
class MilkTeaFactory(AbstractFactory):
def create_drink(self):
return MilkTea()
def create_cup(self):
return SmallCup()
class StrawberryShakeFactory(AbstractFactory):
def create_drink(self):
return StrawberryShake()
def create_cup(self):
return LargeCup()
# 使用抽象工厂创建饮品和杯子
factory1 = MilkTeaFactory()
drink1 = factory1.create_drink()
cup1 = factory1.create_cup()
drink1.drink() # 输出:喝珍珠奶茶
cup1.use() # 输出:使用小杯子
factory2 = StrawberryShakeFactory()
drink2 = factory2.create_drink()
cup2 = factory2.create_cup()
drink2.drink() # 输出:喝草莓奶昔
cup2.use() # 输出:使用大杯子
优点:可以创建一系列相关的产品对象,减少了客户端需要处理的对象数量。
缺点:结构比较复杂,当需要新增一种产品类型时,需要修改所有的工厂类,违反了 "开闭原则"。
3. 工厂模式口诀
"工厂模式像工厂,对象创建它来管,
简单工厂易扩展,工厂方法更灵活,
抽象工厂管家族,按需选择别搞错。"
4. 适用场景
- 当需要创建多个相关或相似的对象时。
- 当客户端不需要知道具体的产品类,只需要知道产品的类型时。
- 当希望将对象的创建和使用分离开来,提高代码的可维护性和扩展性时。
二、单例模式:保证对象唯一,全局共享数据
1. 什么是单例模式?
单例模式是一种确保一个类只有一个实例,并提供一个全局访问点的设计模式。简单来说,就是这个类在整个程序中只能创建一个对象,而且这个对象可以被全局访问。比如咱们电脑上的任务管理器,不管你打开多少次,始终只有一个实例在运行;还有打印机,全班同学共用一台打印机,这就是单例模式的应用。
在编程中,单例模式通常用于需要全局共享一个对象的场景,比如配置管理器、日志记录器、数据库连接池等。
2. 单例模式的实现方法
在 Python 中,实现单例模式有多种方法,下面介绍几种常用的方式。
(1)重写__new__方法
__new__方法是在类实例化时首先被调用的方法,它负责创建类的实例。我们可以通过重写__new__方法,来确保只创建一个实例。
代码示例:
class Singleton:
_instance = None
def __new__(cls, *args, **kwargs):
if not cls._instance:
cls._instance = super().__new__(cls, *args, **kwargs)
return cls._instance
# 创建单例对象
obj1 = Singleton()
obj2 = Singleton()
print(obj1 is obj2) # 输出:True,说明两个对象是同一个实例
(2)使用装饰器
装饰器的内容可以参考我的另一篇文章《Python的装饰器还是不会?来看看这篇文章(建议收藏)》
装饰器是 Python 中一种强大的特性,我们可以用装饰器来装饰类,使其成为单例类。
代码示例:
def singleton(cls):
instances = {}
def get_instance(*args, **kwargs):
if cls not in instances:
instances[cls] = cls(*args, **kwargs)
return instances[cls]
return get_instance
@singleton
class MySingleton:
def __init__(self, name):
self.name = name
# 创建单例对象
obj1 = MySingleton("张三")
obj2 = MySingleton("李四")
print(obj1.name) # 输出:张三
print(obj2.name) # 输出:张三,说明后面的赋值不会改变实例的属性,因为对象是同一个
print(obj1 is obj2) # 输出:True
(3)基于模块
Python 中的模块本身就是单例的,当我们导入一个模块时,模块中的代码只会执行一次,模块中的变量、类等都是单例的。所以我们可以把需要作为单例的类定义在一个模块中,然后通过导入模块来使用单例对象。
代码示例:
创建一个模块singleton_module.py,内容如下:
class Singleton:
def __init__(self, name):
self.name = name
instance = Singleton("单例对象")
在其他文件中使用:
from singleton_module import instance
obj1 = instance
obj2 = instance
print(obj1 is obj2) # 输出:True
3. 单例模式口诀
"单例模式保唯一,全局使用很方便,
__new__方法来重写,装饰模块也能行,
使用场景要牢记,配置日志数据库。"
4. 适用场景
- 当类需要有且只有一个实例,并且该实例需要被全局访问时。
- 当需要节省系统资源,避免重复创建和销毁对象时,比如数据库连接池。
- 当需要确保数据的一致性,避免多个实例之间的数据不一致时。
三、适配器模式:解决接口不兼容问题,让旧代码焕发新生
1. 什么是适配器模式?
适配器模式就像我们日常生活中的充电器转换头。比如你去国外旅行,当地的插座接口和你的充电器接口不兼容,这时候你就需要一个转换头,把当地的插座接口转换成你充电器能使用的接口。在编程中,适配器模式就是用来解决两个接口不兼容的问题,它通过创建一个适配器类,将一个类的接口转换成另一个类所期望的接口,从而让原本不兼容的类可以一起工作。
2. 适配器模式的实现
适配器模式有两种类型:对象适配器和类适配器。在 Python 中,由于支持多重继承,类适配器也可以实现,但更常用的是对象适配器,因为它更灵活,不需要继承原类。
(1)对象适配器
对象适配器通过组合的方式,将被适配的对象作为适配器类的一个成员变量,然后在适配器类中实现目标接口。
代码示例:
假设我们有一个旧的支付接口OldPayment,它有一个pay_old方法,而新的支付系统需要使用NewPayment接口,它有一个pay_new方法。为了让旧的支付接口能在新的系统中使用,我们需要创建一个适配器类PaymentAdapter。
class OldPayment:
def pay_old(self, amount):
print(f"旧支付方式支付了{amount}元")
class NewPayment:
def pay_new(self, payment, amount):
payment.pay_old(amount) # 新系统需要调用pay_new方法,传入一个具有pay_old方法的对象
class PaymentAdapter:
def __init__(self, old_payment):
self.old_payment = old_payment
def pay_new(self, amount): # 实现新接口的pay_new方法
self.old_payment.pay_old(amount)
# 使用适配器
old_payment = OldPayment()
adapter = PaymentAdapter(old_payment)
new_payment = NewPayment()
new_payment.pay_new(adapter, 100) # 输出:旧支付方式支付了100元
(2)类适配器(使用多重继承)
类适配器通过继承被适配的类和实现目标接口来实现。
代码示例:
class OldPayment:
def pay_old(self, amount):
print(f"旧支付方式支付了{amount}元")
class NewPaymentInterface:
def pay_new(self, amount):
pass
class PaymentAdapter(OldPayment, NewPaymentInterface):
def pay_new(self, amount):
self.pay_old(amount)
# 使用适配器
adapter = PaymentAdapter()
adapter.pay_new(100) # 输出:旧支付方式支付了100元
3. 适配器模式口诀
"适配器像转换头,接口不符它来救,对象适配用组合,类适配用继承,新旧代码连一连,和谐工作乐无边。"
4. 适用场景
- 当需要使用一个已经存在的类,而它的接口不符合你的需求时。
- 当你想创建一个可以复用的类,该类可以与其他接口不兼容的类一起工作时。
- 当你需要在不修改原类代码的情况下,扩展类的功能时。
3 个设计模式的核心要点对比
设计模式 | 核心作用 | 典型场景 | 实现关键 | 口诀记忆 |
工厂模式 | 统一管理对象创建 | 对象创建逻辑复杂 / 需解耦 | 工厂类封装创建逻辑 | 工厂模式像工厂,对象创建它来管 |
单例模式 | 保证全局唯一实例 | 全局共享资源 / 配置 | 重写__new__或用装饰器 | 单例模式保唯一,全局使用很方便 |
适配器模式 | 转换不兼容接口 | 新旧系统对接 / 接口适配 | 创建适配器类转换接口 | 适配器像转换头,接口不符它来救 |
设计模式是编程经验的总结,不是万能的银弹。在实际开发中,要根据具体的场景选择合适的设计模式,不要为了使用设计模式而使用设计模式。
猜你喜欢
- 2025-05-22 副业兼职不同适合上班族的25个副业(上),每个做好都月入过万
- 2025-05-22 突破爬虫瓶颈:Python爬虫核心能力提升与案例实操
- 2025-05-22 超实用!这是我见过最全面的Python入门教程,新手不要错过免费送
- 2025-05-22 Python生成器入门:用“按需生产”思维处理海量数据
- 2025-05-22 用Python进行机器学习(16)-内容总结
- 2025-05-22 Python办公自动化系列篇之十:总结
- 2025-05-22 小学生Python编程入门-1.什么是编程?
- 2025-05-22 用Python开发日常小软件,让生活与工作更高效!附实例代码
- 2025-05-22 丢掉Excel,手把手教你用Python做可视化,还能调节动画丝滑度
- 2025-05-22 百看不如一练的70个Python实战项目(附高清PDF完整版教程)
- 05-25Python 3.14 t-string 要来了,它与 f-string 有何不同?
- 05-25Python基础元素语法总结
- 05-25Python中的变量是什么东西?
- 05-25新手常见的python报错及解决方案
- 05-2511-Python变量
- 05-2510个每个人都是需要知道Python问题
- 05-25Python编程:轻松掌握函数定义、类型及其参数传递方式
- 05-25Python基础语法
- 257℃Python短文,Python中的嵌套条件语句(六)
- 257℃python笔记:for循环嵌套。end=""的作用,图形打印
- 256℃PythonNet:实现Python与.Net代码相互调用!
- 251℃Python操作Sqlserver数据库(多库同时异步执行:增删改查)
- 251℃Python实现字符串小写转大写并写入文件
- 106℃原来2025是完美的平方年,一起探索六种平方的算吧
- 91℃Python 和 JavaScript 终于联姻了!PythonMonkey 要火?
- 81℃Ollama v0.4.5-v0.4.7 更新集合:Ollama Python 库改进、新模型支持
- 最近发表
- 标签列表
-
- python中类 (31)
- python 迭代 (34)
- python 小写 (35)
- python怎么输出 (33)
- python 日志 (35)
- python语音 (31)
- python 工程师 (34)
- python3 安装 (31)
- python音乐 (31)
- 安卓 python (32)
- python 小游戏 (32)
- python 安卓 (31)
- python聚类 (34)
- python向量 (31)
- python大全 (31)
- python次方 (33)
- python桌面 (32)
- python总结 (34)
- python浏览器 (32)
- python 请求 (32)
- python 前端 (32)
- python验证码 (33)
- python 题目 (32)
- python 文件写 (33)
- python中的用法 (32)