从Blender/Unity转战Godot?先搞定编辑器布局的“水土不服”(对比与迁移指南)
2026/4/22 1:22:17
欢迎来到第68天!
在昨天的课程中,我们学习了如何优雅地创建对象(单例、工厂)。今天,我们来关注对象之间的交互。
本节内容:
functools.partial应用核心思想:一对多依赖。一个主题 (Subject),多个观察者 (Observer)。
# 主题 (被观察者)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 收到新闻: ...# [短信中心] ...在 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("设计模式详解")核心思想:把算法封装成类(或函数),让它们可以互相替换。
场景:商场打折。
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.0Python 中函数是一等公民,没必要非得定义类。
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如果策略函数需要额外的参数(比如打 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. 观察者 (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)class VIPOrder(Order),行为就固定了。order.strategy = new_strategy。不算。装饰器是结构型模式(Wrapper),用于增强功能。观察者是行为型模式,用于解耦通知。
关键要点:
Sorter类,可以接受不同的排序策略(如bubble_sort,quick_sort),对列表进行排序。use_weapon()在装备"剑"时是近战伤害,装备"弓"时是远程伤害。Day 69:C/C++ 扩展 (CTypes/Cython)- Python 跑得慢怎么办?设计模式救不了你,但 C 语言可以!明天我们学习如何用 Python 调用 C 代码,获得百倍性能提升。
系列导航: