news 2026/2/7 9:53:11

Day 68:【99天精通Python】设计模式 (Design Patterns) 下篇 - 观察者与策略

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Day 68:【99天精通Python】设计模式 (Design Patterns) 下篇 - 观察者与策略

Day 68:【99天精通Python】设计模式 (Design Patterns) 下篇 - 观察者与策略

前言

欢迎来到第68天!

在昨天的课程中,我们学习了如何优雅地创建对象(单例、工厂)。今天,我们来关注对象之间的交互

  • 观察者模式 (Observer):当一个对象状态改变时,自动通知所有依赖它的对象。(例如:UP主发布视频,粉丝收到推送)。
  • 策略模式 (Strategy):定义一系列算法,让它们可以互换。(例如:地图导航可以选择"最快"、“最短”、"不走高速"等不同策略)。

本节内容:

  • 观察者模式:发布-订阅机制
  • 策略模式:算法的封装与替换
  • Python 内置的functools.partial应用
  • 实战练习:电商促销系统

一、观察者模式 (Observer)

核心思想:一对多依赖。一个主题 (Subject),多个观察者 (Observer)。

1.1 经典实现

# 主题 (被观察者)classNewsChannel:def__init__(self):self._subscribers=[]# 订阅者列表defattach(self,observer):self._subscribers.append(observer)defdetach(self,observer):self._subscribers.remove(observer)defnotify(self,news):forsubinself._subscribers:sub.update(news)# 观察者 (接口)classSubscriber:defupdate(self,news):raiseNotImplementedError# 具体观察者classUser(Subscriber):def__init__(self,name):self.name=namedefupdate(self,news):print(f"{self.name}收到新闻:{news}")classSMSCenter(Subscriber):defupdate(self,news):print(f"[短信中心] 正在发送短信:{news}")# 使用channel=NewsChannel()user1=User("Alice")user2=User("Bob")sms=SMSCenter()channel.attach(user1)channel.attach(user2)channel.attach(sms)channel.notify("Python 3.14 发布啦!")# 输出:# Alice 收到新闻: ...# Bob 收到新闻: ...# [短信中心] ...

1.2 Pythonic 实现:信号机制

在 Django 或 PyQt 中,常用信号 (Signal)来实现观察者模式。我们可以写一个简单的 Signal 类。

classSignal:def__init__(self):self._handlers=[]defconnect(self,handler):self._handlers.append(handler)defemit(self,*args,**kwargs):forhandlerinself._handlers:handler(*args,**kwargs)# 使用video_uploaded=Signal()defnotify_fans(title):print(f"通知粉丝: 新视频《{title}》上线了")defupdate_db(title):print(f"数据库记录: 视频《{title}》已入库")video_uploaded.connect(notify_fans)video_uploaded.connect(update_db)video_uploaded.emit("设计模式详解")

二、策略模式 (Strategy)

核心思想:把算法封装成类(或函数),让它们可以互相替换。

场景:商场打折。

  • 策略 A:打八折。
  • 策略 B:满 100 减 20。
  • 策略 C:VIP 半价。

2.1 传统实现 (面向对象)

fromabcimportABC,abstractmethod# 策略接口classDiscountStrategy(ABC):@abstractmethoddefcalculate(self,price):pass# 具体策略classNormalStrategy(DiscountStrategy):defcalculate(self,price):returnpriceclassTenPercentOffStrategy(DiscountStrategy):defcalculate(self,price):returnprice*0.9classOver100Minus20Strategy(DiscountStrategy):defcalculate(self,price):ifprice>=100:returnprice-20returnprice# 上下文 (使用策略的类)classOrder:def__init__(self,price,strategy:DiscountStrategy):self.price=price self.strategy=strategydeffinal_price(self):returnself.strategy.calculate(self.price)# 使用order=Order(100,TenPercentOffStrategy())print(f"折后价:{order.final_price()}")# 90.0

2.2 Pythonic 实现:函数即对象

Python 中函数是一等公民,没必要非得定义类。

deften_percent_off(price):returnprice*0.9defover_100_minus_20(price):returnprice-20ifprice>=100elsepriceclassOrder:def__init__(self,price,strategy_func):self.price=price self.func=strategy_funcdeffinal_price(self):returnself.func(self.price)# 使用order=Order(200,over_100_minus_20)print(f"折后价:{order.final_price()}")# 180

2.3 进阶:使用 partial 固定参数

如果策略函数需要额外的参数(比如打 n 折),可以使用functools.partial

fromfunctoolsimportpartialdefdiscount(price,rate):returnprice*rate# 创建一个 "打8折" 的策略strategy_80=partial(discount,rate=0.8)order=Order(100,strategy_80)print(order.final_price())# 80.0

三、实战练习:电商促销系统

结合观察者和策略模式。

  1. 观察者:订单支付成功后,通知库存系统(扣减)、通知物流系统(发货)、通知积分系统(加分)。
  2. 策略:根据用户等级(普通、VIP)自动选择不同的计算价格策略。
# --- 1. 观察者 (Event Bus) ---classEventBus:def__init__(self):self.listeners={}defsubscribe(self,event_type,listener):ifevent_typenotinself.listeners:self.listeners[event_type]=[]self.listeners[event_type].append(listener)defpublish(self,event_type,data):ifevent_typeinself.listeners:forlistenerinself.listeners[event_type]:listener(data)bus=EventBus()# --- 2. 策略 (Pricing) ---defvip_pricing(price):returnprice*0.8defnormal_pricing(price):returnprice# --- 3. 业务逻辑 ---defon_paid(order):print(f"[库存] 扣减商品:{order['item']}")defon_paid_notify(order):print(f"[短信] 您的订单{order['id']}已支付")# 注册监听bus.subscribe("order_paid",on_paid)bus.subscribe("order_paid",on_paid_notify)classOrderSystem:defcreate_order(self,user_type,item,price):# 策略选择strategy=vip_pricingifuser_type=="vip"elsenormal_pricing final=strategy(price)order={"id":1001,"item":item,"total":final}print(f"订单创建,应付:{final}")# 模拟支付print("支付成功...")# 触发观察者bus.publish("order_paid",order)# 运行sys=OrderSystem()sys.create_order("vip","Python Book",100)

四、常见问题

Q1:什么时候用继承,什么时候用策略模式?

  • 继承:是静态的。一旦定义了class VIPOrder(Order),行为就固定了。
  • 策略模式:是动态的。可以在运行时切换策略order.strategy = new_strategy
    原则:多用组合(策略),少用继承。

Q2:Python 的装饰器算不算观察者模式?

不算。装饰器是结构型模式(Wrapper),用于增强功能。观察者是行为型模式,用于解耦通知。


五、小结

设计模式 (行为)

观察者 Observer

策略 Strategy

发布-订阅 (Pub-Sub)

解耦核心逻辑与副作用

应用: 信号、事件驱动

封装算法

运行时切换

消除 if-else

应用: 支付方式、折扣

关键要点

  1. 观察者模式:一方有难,八方支援(一方变动,通知八方)。
  2. 策略模式:条条大路通罗马(多种算法,随意切换)。
  3. Python 的函数式特性(函数作为参数)让这两个模式实现起来非常简洁。

六、课后作业

  1. 股票监控器:使用观察者模式。当股票价格变动时,通知:控制台打印器、邮件发送器(Day 43)、日志记录器(Day 33)。
  2. 排序策略:编写一个Sorter类,可以接受不同的排序策略(如bubble_sort,quick_sort),对列表进行排序。
  3. 游戏角色:设计一个游戏角色类,使用策略模式实现更换武器(WeaponStrategy)。比如:use_weapon()在装备"剑"时是近战伤害,装备"弓"时是远程伤害。

下节预告

Day 69:C/C++ 扩展 (CTypes/Cython)- Python 跑得慢怎么办?设计模式救不了你,但 C 语言可以!明天我们学习如何用 Python 调用 C 代码,获得百倍性能提升。


系列导航

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

树莓派5安装ROS2高效配置方法总结

树莓派5安装ROS2:从零开始的高效部署实战 你是不是也经历过这样的场景?刚拿到崭新的树莓派5,满心欢喜地想搭建一个机器人控制系统,结果在“安装ROS2”这一步卡了整整三天——依赖报错、编译失败、版本冲突……最后只能放弃&#…

作者头像 李华
网站建设 2026/2/5 11:43:19

Intel平台下eSPI枚举过程解析:深度剖析

Intel平台下eSPI枚举过程解析:从协议到实战的深度拆解你有没有遇到过这样的情况——笔记本明明按了电源键,却像“死机”一样毫无反应?或者系统进入睡眠后无法唤醒,风扇狂转、屏幕黑屏?在排查这类低功耗管理故障时&…

作者头像 李华
网站建设 2026/2/5 21:11:33

GTE中文语义相似度服务代码实例:自动化标注系统开发

GTE中文语义相似度服务代码实例:自动化标注系统开发 1. 引言 1.1 业务场景描述 在自然语言处理(NLP)的实际工程落地中,文本语义相似度计算是一项高频且关键的需求。无论是智能客服中的意图匹配、推荐系统中的内容去重&#xff…

作者头像 李华
网站建设 2026/2/3 22:15:54

想换模型怎么操作?麦橘超然扩展性说明

想换模型怎么操作?麦橘超然扩展性说明 1. 引言:轻量化图像生成的可扩展性需求 随着AI绘画在个人设备和边缘计算场景中的普及,用户对模型多样性的需求日益增长。尽管“麦橘超然 - Flux 离线图像生成控制台”默认集成了 majicflus_v1 模型并采…

作者头像 李华
网站建设 2026/2/5 18:51:40

Z-Image-ComfyUI工作流分享:导出导入JSON文件的操作步骤

Z-Image-ComfyUI工作流分享:导出导入JSON文件的操作步骤 1. 引言 1.1 业务场景描述 在当前AIGC(人工智能生成内容)快速发展的背景下,图像生成模型的应用日益广泛。Z-Image-ComfyUI作为基于阿里最新开源文生图大模型Z-Image的可…

作者头像 李华
网站建设 2026/2/7 3:07:35

树莓派换源零基础指南:网络环境要求

树莓派换源实战指南:从卡顿到飞速的秘诀你有没有遇到过这种情况:刚入手树莓派,兴致勃勃地打开终端准备安装Python库或者升级系统,结果一条sudo apt update执行下去,半天不动,进度条像被冻住了一样&#xff…

作者头像 李华