观察者模式(Observer Pattern)
观察者模式是一种设计模式,用于定义对象间的一对多依赖关系,当一个对象的状态发生变化时,其所有依赖者(观察者)都会收到通知并更新。
在 C# 中,事件和事件处理程序非常适合实现观察者模式。
实现代码
以下代码展示了如何使用 C# 中的事件和事件处理程序实现一个简单的观察者模式:
using System;
using System.Collections.Generic;
// 定义一个事件发布者(Subject)
public class Subject
{
// 定义事件
public event EventHandler NotifyObservers;
// 更新状态并通知观察者
private string _state;
public string State
{
get => _state;
set
{
_state = value;
Console.WriteLine($"Subject: State has changed to {_state}");
OnNotifyObservers(_state); // 触发事件
}
}
// 触发事件的方法
protected virtual void OnNotifyObservers(string state)
{
NotifyObservers?.Invoke(this, state);
}
}
// 定义一个观察者(Observer)
public class Observer
{
private readonly string _name;
public Observer(string name)
{
_name = name;
}
// 观察者的处理方法
public void Update(object sender, string state)
{
Console.WriteLine($"Observer {_name}: Received state update: {state}");
}
}
// 主程序
class Program
{
static void Main(string[] args)
{
// 创建事件发布者(主题)
Subject subject = new Subject();
// 创建观察者
Observer observer1 = new Observer("A");
Observer observer2 = new Observer("B");
// 订阅主题的通知
subject.NotifyObservers += observer1.Update;
subject.NotifyObservers += observer2.Update;
// 更改状态,触发通知
subject.State = "State 1";
subject.State = "State 2";
// 取消一个观察者的订阅
subject.NotifyObservers -= observer1.Update;
// 更改状态,验证是否少一个观察者
subject.State = "State 3";
}
}
运行结果
Subject: State has changed to State 1
Observer A: Received state update: State 1
Observer B: Received state update: State 1
Subject: State has changed to State 2
Observer A: Received state update: State 2
Observer B: Received state update: State 2
Subject: State has changed to State 3
Observer B: Received state update: State 3
实现关键点
- 事件声明:
- 使用 event 关键字定义事件,确保其他类只能订阅或取消订阅,而不能直接触发事件。
- NotifyObservers 是一个泛型 EventHandler
,方便传递参数。 - 订阅与取消订阅:
- 使用 += 订阅事件,使用 -= 取消订阅事件。
- 事件触发:
- 在 State 属性的 setter 中,当状态改变时,调用 OnNotifyObservers 方法触发事件。
- 事件处理器:
- Observer 类中的 Update 方法被用作事件处理器,它会在事件触发时被调用。
优点
- 松耦合:发布者和观察者通过事件进行交互,互相不知道彼此的细节。
- 动态订阅:观察者可以动态添加或移除。
- 扩展性强:可以轻松地添加新观察者,而无需修改现有代码。
适用场景
- GUI 应用程序:按钮点击事件通知多个 UI 元素。
- 消息通知系统:发布者通知多个订阅者。
- 数据模型更新:模型变化时通知视图更新(MVVM、MVC 模式)。
改进方向
- 多线程环境下的线程安全性:
- 使用 Interlocked.CompareExchange 确保事件订阅和触发的线程安全。
- 弱引用防止内存泄漏:
- 如果观察者对象被销毁但未取消订阅,可能导致内存泄漏。
- 使用 WeakEventManager(如 WPF 提供的)来管理事件。
通过这种实现方式,可以优雅地实现 C# 中的观察者模式,充分利用语言本身对事件和委托的支持。