行为设计模式是一类用于描述对象之间通信与职责分配的设计模式,关注“对象之间的交互”和“职责的分配”。你提到的四种模式——观察者(Observer)、策略(Strategy)、命令(Command)和职责链(Chain of Responsibility)——均属于经典GoF 23种设计模式中的行为型模式,各自解决不同场景下的行为解耦与动态变化问题:
- 观察者模式:定义对象间一对多的依赖关系,当一个对象状态改变时,所有依赖它的对象自动得到通知并更新(如事件监听、MVC中的View-Model联动)。
- 策略模式:封装一系列算法,使它们可以互相替换,让算法的变化独立于使用它的客户端(如支付方式选择:微信支付、支付宝、银行卡等策略可动态切换)。
- 命令模式:将请求封装为对象,从而可用不同的请求对客户进行参数化、支持撤销/重做、日志记录和队列操作(如GUI按钮点击、宏命令、任务调度系统)。
- 职责链模式:使多个对象都有机会处理请求,避免请求发送者与接收者耦合,将这些对象连成一条链,并沿链传递请求,直到被处理(如审批流程:组长→部门经理→HR→CEO逐级处理)。
这四者共性在于:降低对象间的紧耦合,提升行为的可扩展性与可维护性;差异在于关注点不同——观察者聚焦“状态变更通知”,策略聚焦“算法替换”,命令聚焦“请求封装与控制”,职责链聚焦“请求分发与响应权移交”。
# 示例:简易策略模式实现(支付策略)fromabcimportABC,abstractmethodclassPaymentStrategy(ABC):@abstractmethoddefpay(self,amount:float)->str:passclassWeChatPay(PaymentStrategy):defpay(self,amount:float)->str:returnf"微信支付{amount}元"classAlipay(PaymentStrategy):defpay(self,amount:float)->str:returnf"支付宝支付{amount}元"classPaymentContext:def__init__(self,strategy:PaymentStrategy):self._strategy=strategydefexecute_payment(self,amount:float)->str:returnself._strategy.pay(amount)# 使用ctx=PaymentContext(WeChatPay())print(ctx.execute_payment(99.9))# 微信支付 99.9 元在观察者模式中,内存泄漏常源于循环引用(circular reference):被观察者(Subject)持有了观察者(Observer)的强引用,而观察者又可能通过回调、闭包或内部类等方式持有被观察者的引用,导致垃圾回收器无法释放对象(尤其在长期运行系统如GUI应用、服务端事件总线中尤为关键)。
✅ Java 中的典型解决方案:
使用弱引用(
WeakReference)管理观察者
将观察者存入WeakReference<Observer>列表,使GC可在无其他强引用时回收观察者,避免被观察者阻止其销毁:publicclassSubject{privatefinalList<WeakReference<Observer>>observers=newArrayList<>();publicvoidaddObserver(Observerobs){observers.add(newWeakReference<>(obs));}publicvoidnotifyObservers(){// 过滤已回收的观察者observers.removeIf(ref->ref.get()==null);observers.forEach(ref->{Observerobs=ref.get();if(obs!=null)obs.update(this);});}}显式解注册(Unregister)+
try-finally/AutoCloseable
要求观察者在生命周期结束前调用removeObserver(),配合try-with-resources或Disposable接口(如RxJava的Disposable)确保清理。使用
java.util.concurrent.CopyOnWriteArrayList+ 显式管理
线程安全,但需配合手动移除逻辑;适用于观察者数量少、变更不频繁场景。框架级方案:
- Android 中
LiveData内部使用LifecycleOwner绑定生命周期,自动解注册; - Spring 的
ApplicationEventPublisher配合@EventListener与SmartLifecycle实现自动销毁感知。
- Android 中
✅ Python 中的典型解决方案:
使用
weakref.WeakKeyDictionary或weakref.WeakSetWeakKeyDictionary以观察者为 key,自动在观察者被回收时剔除条目(要求观察者是可哈希的);WeakSet更通用(支持任意对象):importweakrefclassSubject:def__init__(self):self._observers=weakref.WeakSet()# 自动清理已销毁的observerdefattach(self,observer):self._observers.add(observer)defnotify(self,data):# WeakSet 迭代时自动跳过已回收对象forobsinlist(self._observers):# list() 防止迭代中修改obs.update(data)避免闭包捕获
self引用(尤其在 lambda 或嵌套函数中)
❌ 危险示例:defregister(self,obj):self.observers.append(lambda:self.handle(obj))# 捕获 self → 循环引用!✅ 安全替代:用
functools.partial或显式传参,或改用绑定方法(obj.method是 bound method,但需确保obj不反向引用self)。上下文管理器(
with语句)或__del__辅助清理(慎用)
更推荐显式unregister()+ 上下文协议(如contextlib.closing),因__del__执行时机不确定且不可靠。现代方案:
asyncio事件总线 +weakref.ref回调
在异步系统中,结合asyncio.create_task()和弱引用回调,避免任务长期持有对象引用。
✅共性最佳实践:
- 观察者应无状态或弱依赖被观察者;
- 被观察者不持有观察者的业务逻辑引用,仅保留通知能力;
- 在 GUI/Android/前端框架中,严格绑定生命周期(如
onDestroy()、useEffect cleanup); - 使用静态分析工具(Java:
LeakCanary;Python:objgraph、tracemalloc)检测潜在泄漏。