观察者模式属于行为型设计模式,核心思想是定义对象间的一对多依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知并被自动更新。在C#中,我们可以通过多种方式实现该模式,适配不同的开发场景。

基于接口的传统观察者模式实现
这种实现方式符合观察者模式的经典定义,通过抽象接口解耦被观察者和观察者,适合需要严格遵循设计模式规范的场景。
定义观察者接口
首先定义观察者接口,所有具体观察者都需要实现该接口,包含接收通知的方法:
// 观察者接口
public interface IObserver
{
// 接收被观察者状态变更通知
void Update(string state);
}
// 具体观察者A
public class ConcreteObserverA : IObserver
{
private string _name;
public ConcreteObserverA(string name)
{
_name = name;
}
public void Update(string state)
{
Console.WriteLine($"{_name} 收到状态变更通知,新状态为:{state}");
}
}
// 具体观察者B
public class ConcreteObserverB : IObserver
{
private string _name;
public ConcreteObserverB(string name)
{
_name = name;
}
public void Update(string state)
{
Console.WriteLine($"{_name} 收到状态变更通知,新状态为:{state}");
}
}
定义被观察者抽象类
被观察者需要维护观察者列表,提供添加、移除观察者以及通知所有观察者的方法:
// 被观察者抽象类
public abstract class Subject
{
// 存储所有观察者的列表
private List<IObserver> _observers = new List<IObserver>();
// 添加观察者
public void Attach(IObserver observer)
{
_observers.Add(observer);
}
// 移除观察者
public void Detach(IObserver observer)
{
_observers.Remove(observer);
}
// 通知所有观察者
public void Notify(string state)
{
foreach (var observer in _observers)
{
observer.Update(state);
}
}
}
实现具体被观察者
具体被观察者继承抽象被观察者,维护自身状态,状态变更时触发通知:
// 具体被观察者
public class ConcreteSubject : Subject
{
private string _state;
// 被观察者状态
public string State
{
get { return _state; }
set
{
_state = value;
// 状态变更时通知所有观察者
Notify(_state);
}
}
}
使用示例
将观察者和被观察者组合使用,验证模式效果:
class Program
{
static void Main(string[] args)
{
// 创建被观察者
ConcreteSubject subject = new ConcreteSubject();
// 创建观察者
IObserver observerA = new ConcreteObserverA("观察者A");
IObserver observerB = new ConcreteObserverB("观察者B");
// 注册观察者
subject.Attach(observerA);
subject.Attach(observerB);
// 修改被观察者状态,触发通知
subject.State = "状态1";
subject.State = "状态2";
// 移除一个观察者后再修改状态
subject.Detach(observerA);
subject.State = "状态3";
}
}
基于C#事件委托的观察者模式实现
C#内置的事件和委托机制天然适配观察者模式,实现更简洁,是实际开发中最常用的方式。
定义事件和委托
被观察者定义委托和事件,观察者只需订阅事件即可接收通知:
// 状态变更委托
public delegate void StateChangeHandler(string newState);
public class EventSubject
{
// 状态变更事件
public event StateChangeHandler StateChanged;
private string _state;
public string State
{
get { return _state; }
set
{
_state = value;
// 触发事件,通知所有订阅者
StateChanged?.Invoke(_state);
}
}
}
观察者订阅事件
观察者不需要实现特定接口,只需定义和委托匹配的方法,订阅被观察者的事件:
class Program
{
static void Main(string[] args)
{
EventSubject subject = new EventSubject();
// 定义观察者方法
void ObserverMethod1(string state)
{
Console.WriteLine($"观察者1 收到通知,新状态:{state}");
}
void ObserverMethod2(string state)
{
Console.WriteLine($"观察者2 收到通知,新状态:{state}");
}
// 订阅事件
subject.StateChanged += ObserverMethod1;
subject.StateChanged += ObserverMethod2;
// 修改状态触发通知
subject.State = "事件状态1";
subject.State = "事件状态2";
// 取消订阅
subject.StateChanged -= ObserverMethod1;
subject.State = "事件状态3";
}
}
两种实现方式的对比
两种方式各有适用场景,我们可以通过以下表格快速选择:
| 实现方式 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| 接口实现 | 严格符合设计模式定义,解耦更彻底,可跨语言复用思路 | 代码量较多,需要手动维护观察者列表 | 需要严格遵循设计模式规范,或需要自定义通知逻辑的场景 |
| 事件委托实现 | 代码简洁,无需手动维护观察者列表,C#原生支持 | 依赖C#语言特性,事件只能在声明它的类内部触发 | 纯C#项目,追求开发效率,不需要复杂通知逻辑的场景 |
实现注意事项
- 避免在观察者通知方法中执行耗时操作,否则会阻塞被观察者的状态更新流程。
- 如果观察者需要被观察者传递更多上下文信息,可以定义包含多参数的委托或事件参数类,继承
EventArgs。 - 当观察者不再需要接收通知时,及时取消订阅事件或移除观察者,避免内存泄漏。
- 多线程场景下修改被观察者状态时,需要注意线程安全,可对通知过程加锁。
C#观察者模式Observer设计模式事件委托修改时间:2026-06-08 20:39:28