在 .NET 平台下,通过委托和事件这两种机制,观察者模式具体是如何落地实现的?请结合设计思路和代码示例说明。
考察说明
考查对委托、事件机制的理解,以及如何用它们实现观察者模式。
回答思路
- 【回答框架 1】观察者模式的核心是定义一对多依赖,让多个观察者对象能自动收到主题状态变化的通知。在 .NET 中,委托是类型安全的函数指针,事件是对委托的封装,专门用于发布-订阅场景。
- 【回答框架 2】实现时,先在主题类中声明事件,例如 public event EventHandler<EventArgs> StateChanged,并以 OnStateChanged 方法作为受保护的虚方法统一触发事件,确保外部只能通过订阅来响应。
- 【回答框架 3】观察者通过 += 操作符订阅事件,在事件处理程序中执行自己的更新逻辑;当主题状态改变时,调用 OnStateChanged,所有订阅者依次收到通知。移除订阅使用 -= 操作符,注意避免内存泄漏。
- 【回答框架 4】事件相比裸委托,限制了外部只能进行 += 和 -= 操作,不能直接调用或赋值,符合封装原则,也更安全。.NET 的 EventHandler<T> 是标准的事件委托模式,建议遵循该约定。
- 【回答框架 5】实际开发中,可以使用弱事件模式或在释放时显式取消订阅,以防止持有窗口等长生命周期对象而导致垃圾回收无法回收的问题。
- 【关键点 1】事件是委托的封装,外部只能订阅和取消订阅,不能直接触发。
- 【关键点 2】标准模式:public event EventHandler<T> Xxx,配合 protected virtual OnXxx 方法触发。
- 【关键点 3】观察者通过 += 订阅,-= 退订,主题变更时自动通知所有订阅者。
- 【关键点 4】使用标准委托 EventHandler<T> 遵循 .NET 设计规范。
- 【关键点 5】注意解除订阅或用弱事件,避免内存泄漏。
- 【易错点 1】误用裸委托,外部可直接调用或赋值,破坏封装。
- 【易错点 2】忘记取消订阅,导致内存泄漏,尤其当观察者是长生命周期对象时。
- 【易错点 3】事件处理异常会中断后续订阅者执行,需在事件处理中做好异常隔离。