news 2026/4/1 12:21:12

Day 67:【99天精通Python】设计模式 (Design Patterns) 上篇 - 单例与工厂

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Day 67:【99天精通Python】设计模式 (Design Patterns) 上篇 - 单例与工厂

Day 67:【99天精通Python】设计模式 (Design Patterns) 上篇 - 单例与工厂

前言

欢迎来到第67天!

写代码就像盖房子。初学者只要能把砖头砌起来,房子不塌就行。但资深工程师追求的是结构优雅、易于维护、可扩展

设计模式 (Design Patterns)就是前人总结出来的"建筑图纸"。遇到什么问题,套用什么模式,往往能事半功倍。

本节内容:

  • 设计模式的三大分类
  • 单例模式 (Singleton):确保一个类只有一个实例
  • 工厂模式 (Factory):批量生产对象的工厂
  • Pythonic 的实现方式

一、设计模式分类

通常分为三类:

  1. 创建型 (Creational):关注对象的创建过程(如:单例、工厂、建造者)。
  2. 结构型 (Structural):关注类和对象的组合(如:适配器、装饰器、代理)。
  3. 行为型 (Behavioral):关注对象之间的通信(如:观察者、策略、责任链)。

今天我们先攻克最常用的两个创建型模式


二、单例模式 (Singleton)

场景

  • 一个系统只能有一个数据库连接池。
  • 全局的配置管理器 (Config Manager) 只能有一份。
  • 也就是:无论你调用多少次类,它返回的永远是同一个实例。

2.1 传统实现:使用__new__

__new__是 Python 中真正负责创建对象的方法(比__init__更早执行)。

classSingleton:_instance=None# 用于存储唯一实例def__new__(cls,*args,**kwargs):ifnotcls._instance:print("创建新的实例...")# 调用父类的 __new__ 创建实例cls._instance=super().__new__(cls)returncls._instancedef__init__(self,name):self.name=name# 测试s1=Singleton("配置A")s2=Singleton("配置B")print(s1iss2)# True (它们是同一个对象)print(s1.name)# 配置B (s2 初始化时覆盖了 s1 的属性)print(s2.name)# 配置B

2.2 Pythonic 实现:使用装饰器

写一个装饰器,把类包起来,让它变成单例。

defsingleton(cls):instances={}defwrapper(*args,**kwargs):ifclsnotininstances:instances[cls]=cls(*args,**kwargs)returninstances[cls]returnwrapper@singletonclassDatabase:def__init__(self):print("连接数据库...")db1=Database()db2=Database()# 不会再次打印 "连接数据库..."print(db1isdb2)# True

2.3 最简单的实现:模块 (Module)

其实,Python 的模块本身就是单例
因为 Python 导入模块时会缓存,第二次导入直接从缓存拿。

# config.pyclassConfig:passsettings=Config()# main.py# from config import settings# 无论在哪里导入 settings,它都是同一个对象。

三、工厂模式 (Factory)

场景

  • 你去买车,你不需要知道车是怎么造出来的,你只要告诉工厂"我要一辆特斯拉",工厂就给你一辆车。
  • 解耦:将对象的创建使用分离。

3.1 简单工厂 (Simple Factory)

一个工厂类,根据参数决定生产什么产品。

classDog:defspeak(self):return"汪汪"classCat:defspeak(self):return"喵喵"classAnimalFactory:@staticmethoddefcreate_animal(animal_type):ifanimal_type=="dog":returnDog()elifanimal_type=="cat":returnCat()else:raiseValueError("未知动物类型")# 使用pet1=AnimalFactory.create_animal("dog")print(pet1.speak())

缺点:如果新增一种动物(如 Pig),必须修改create_animal的源代码(违反开闭原则)。

3.2 工厂方法 (Factory Method)

定义一个创建对象的接口,让子类决定实例化哪一个类。

# 抽象工厂基类classFactory:defcreate(self):raiseNotImplementedError# 具体工厂classDogFactory(Factory):defcreate(self):returnDog()classCatFactory(Factory):defcreate(self):returnCat()# 使用dog_factory=DogFactory()pet=dog_factory.create()print(pet.speak())

3.3 注册工厂 (Python 动态特性)

利用 Python 的字典,我们可以实现一个无需修改代码就能扩展的工厂。

classPaymentFactory:_creators={}@classmethoddefregister(cls,type_name,creator_cls):cls._creators[type_name]=creator_cls@classmethoddefget_payment(cls,type_name):creator=cls._creators.get(type_name)ifnotcreator:raiseValueError(f"不支持的支付方式:{type_name}")returncreator()classAliPay:defpay(self):print("支付宝支付")classWeChatPay:defpay(self):print("微信支付")# 注册PaymentFactory.register("alipay",AliPay)PaymentFactory.register("wechat",WeChatPay)# 使用p=PaymentFactory.get_payment("alipay")p.pay()

四、实战练习:日志记录器工厂

结合单例和工厂模式,设计一个日志系统。

  1. LoggerManager是单例。
  2. 提供get_logger(type)方法,根据类型返回FileLoggerConsoleLogger
classConsoleLogger:deflog(self,msg):print(f"[Console]{msg}")classFileLogger:deflog(self,msg):print(f"[File] 写入:{msg}")# 单例装饰器defsingleton(cls):instances={}defwrapper(*args,**kwargs):ifclsnotininstances:instances[cls]=cls(*args,**kwargs)returninstances[cls]returnwrapper@singletonclassLoggerManager:defget_logger(self,log_type):iflog_type=="file":returnFileLogger()else:returnConsoleLogger()# 测试m1=LoggerManager()m2=LoggerManager()print(f"管理器单例检查:{m1ism2}")# Truelog=m1.get_logger("file")log.log("系统启动")

五、小结

设计模式

单例 Singleton

工厂 Factory

new方法

装饰器实现

模块导入 (最推荐)

简单工厂 (if/else)

工厂方法 (子类实现)

注册模式 (字典映射)

关键要点

  1. 单例模式:保证全局唯一。Python 中直接用模块导入是最简单的单例。
  2. 工厂模式:封装创建逻辑。如果逻辑简单,不要过度设计,直接用函数返回对象即可。
  3. 设计模式的初衷是解耦,但不要为了模式而模式(Over-engineering)。

六、课后作业

  1. 数据库连接池:模拟实现一个ConnectionPool类,使用单例模式,保证全局只有一个池子。池子里最多有 5 个连接。
  2. 格式转换工厂:编写一个工厂,根据输入文件的后缀名(.json, .xml, .csv),返回对应的解析器对象(JsonParser,XmlParser…)。
  3. 思考题:在 Day 19 学过的装饰器模式,属于哪一类设计模式?它的作用是什么?

下节预告

Day 68:设计模式 (Design Patterns) 下篇 - 观察者与策略- 如果说创建型模式是造房子,那行为型模式就是房子里的电路系统。明天我们学习如何让对象之间优雅地通信。


系列导航

  • 上一篇:Day 66 - Python操作Kubernetes
  • 下一篇:Day 68 - 设计模式下(待更新)
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/3/27 5:59:56

解放你的音乐收藏:NcmpGui让NCM格式不再成为枷锁

解放你的音乐收藏:NcmpGui让NCM格式不再成为枷锁 【免费下载链接】ncmppGui 一个使用C编写的转换ncm文件的GUI工具 项目地址: https://gitcode.com/gh_mirrors/nc/ncmppGui 你是否曾经遇到过这样的情况:在网易云音乐下载的歌曲,换个设…

作者头像 李华
网站建设 2026/3/29 1:55:34

RexUniNLU简历解析:实体识别与关系抽取

RexUniNLU简历解析:实体识别与关系抽取 1. 技术背景与应用场景 在现代人力资源管理系统中,自动化简历解析已成为提升招聘效率的关键环节。传统方法依赖规则匹配和正则表达式,难以应对中文简历中复杂多变的表述方式。随着深度学习技术的发展…

作者头像 李华
网站建设 2026/3/28 12:31:28

Android系统开发实战:添加自定义开机启动服务

Android系统开发实战:添加自定义开机启动服务 1. 引言 1.1 业务场景描述 在Android系统级开发中,经常需要实现某些功能在设备开机时自动执行,例如初始化硬件配置、启动守护进程、设置系统属性或加载特定驱动模块。这类需求广泛应用于智能终…

作者头像 李华
网站建设 2026/3/14 17:06:15

5个最火TTS镜像推荐:0配置开箱即用,10块钱全试遍

5个最火TTS镜像推荐:0配置开箱即用,10块钱全试遍 你是不是也遇到过这种情况?AI课老师布置作业,要求体验3个语音合成模型并写报告。你兴致勃勃打开GitHub,结果发现几十个TTS项目摆在眼前——名字看不懂、文档全是英文、…

作者头像 李华
网站建设 2026/3/31 4:17:49

ESP32入门指南:一文说清GPIO引脚分配与功能

ESP32 GPIO实战指南:从引脚分配到低功耗设计的完整避坑手册你有没有遇到过这样的情况?代码明明写得没问题,烧录时却卡在“waiting for download”不动了;或者设备上电后反复重启,查了半天才发现是某个按钮接错了引脚。…

作者头像 李华
网站建设 2026/3/28 5:46:32

5分钟快速搞定Axure RP完整汉化:新手零基础教程

5分钟快速搞定Axure RP完整汉化:新手零基础教程 【免费下载链接】axure-cn Chinese language file for Axure RP. Axure RP 简体中文语言包,不定期更新。支持 Axure 9、Axure 10。 项目地址: https://gitcode.com/gh_mirrors/ax/axure-cn 还在为A…

作者头像 李华