观察者模式的核心思想是建立对象间的一对多依赖关系,当目标对象状态变化时,所有依赖它的观察者对象都会收到通知并自动更新。除了常规的实现方式,C#中还有一些另类的观察者模式示例,能适配不同的开发场景。

基于事件委托的轻量实现
利用C#原生的事件机制,可以省去定义抽象观察者接口的繁琐步骤,实现更简洁的观察者模式。
using System;
// 定义发布者类
public class WeatherStation
{
// 定义天气变化事件,携带温度、湿度参数
public event Action<float, float> WeatherChanged;
private float temperature;
private float humidity;
public float Temperature
{
get => temperature;
set
{
temperature = value;
// 温度变化时触发事件
OnWeatherChanged();
}
}
public float Humidity
{
get => humidity;
set
{
humidity = value;
// 湿度变化时触发事件
OnWeatherChanged();
}
}
protected virtual void OnWeatherChanged()
{
WeatherChanged?.Invoke(temperature, humidity);
}
}
// 定义观察者类
public class WeatherDisplay
{
private string name;
public WeatherDisplay(string name)
{
this.name = name;
}
// 订阅事件时绑定的方法
public void Update(float temp, float humi)
{
Console.WriteLine($"{name} 收到天气更新:温度 {temp}℃,湿度 {humi}%");
}
}
class Program
{
static void Main()
{
WeatherStation station = new WeatherStation();
WeatherDisplay display1 = new WeatherDisplay("室内显示屏");
WeatherDisplay display2 = new WeatherDisplay("室外显示屏");
// 绑定事件,相当于订阅通知
station.WeatherChanged += display1.Update;
station.WeatherChanged += display2.Update;
// 修改发布者状态,触发通知
station.Temperature = 25.5f;
station.Humidity = 60.2f;
// 取消一个订阅
station.WeatherChanged -= display1.Update;
station.Temperature = 26.0f;
}
}基于IObservable和IObserver接口的规范实现
C#系统库自带了IObservable<T>和IObserver<T>接口,遵循这两个接口实现观察者模式,更符合.NET生态的规范,也便于和其他响应式组件对接。
using System;
using System.Collections.Generic;
// 定义天气数据载体
public class WeatherData
{
public float Temperature { get; set; }
public float Humidity { get; set; }
}
// 实现发布者接口
public class WeatherObservable : IObservable<WeatherData>
{
private List<IObserver<WeatherData>> observers = new List<IObserver<WeatherData>>();
private WeatherData currentData = new WeatherData();
// 订阅方法,返回可释放对象用于取消订阅
public IDisposable Subscribe(IObserver<WeatherData> observer)
{
if (!observers.Contains(observer))
{
observers.Add(observer);
}
return new Unsubscriber(observers, observer);
}
// 更新天气数据并通知所有观察者
public void UpdateWeather(float temp, float humi)
{
currentData.Temperature = temp;
currentData.Humidity = humi;
foreach (var observer in observers)
{
observer.OnNext(currentData);
}
}
// 结束通知
public void EndTransmission()
{
foreach (var observer in observers)
{
observer.OnCompleted();
}
observers.Clear();
}
// 取消订阅的内部类
private class Unsubscriber : IDisposable
{
private List<IObserver<WeatherData>> _observers;
private IObserver<WeatherData> _observer;
public Unsubscriber(List<IObserver<WeatherData>> observers, IObserver<WeatherData> observer)
{
_observers = observers;
_observer = observer;
}
public void Dispose()
{
if (_observer != null && _observers.Contains(_observer))
{
_observers.Remove(_observer);
}
}
}
}
// 实现观察者接口
public class WeatherObserver : IObserver<WeatherData>
{
private string _name;
private IDisposable _unsubscriber;
public WeatherObserver(string name)
{
_name = name;
}
// 订阅时保存取消订阅的句柄
public virtual void Subscribe(IObservable<WeatherData> provider)
{
_unsubscriber = provider.Subscribe(this);
}
// 收到通知时执行的逻辑
public void OnNext(WeatherData value)
{
Console.WriteLine($"{_name} 收到数据:温度 {value.Temperature}℃,湿度 {value.Humidity}%");
}
public void OnError(Exception error)
{
Console.WriteLine($"{_name} 收到错误:{error.Message}");
}
public void OnCompleted()
{
Console.WriteLine($"{_name} 通知结束");
Unsubscribe();
}
// 取消订阅
public virtual void Unsubscribe()
{
_unsubscriber?.Dispose();
}
}
class Program
{
static void Main()
{
WeatherObservable station = new WeatherObservable();
WeatherObserver observer1 = new WeatherObserver("观察者A");
WeatherObserver observer2 = new WeatherObserver("观察者B");
observer1.Subscribe(station);
observer2.Subscribe(station);
station.UpdateWeather(24.0f, 58.0f);
station.UpdateWeather(25.0f, 61.0f);
observer1.Unsubscribe();
station.UpdateWeather(26.0f, 63.0f);
station.EndTransmission();
}
}基于泛型字典的动态订阅实现
如果需要根据不同的通知类型动态订阅不同的观察者,可以用泛型字典管理不同类型的观察者,实现更灵活的通知分发。
using System;
using System.Collections.Generic;
// 定义通知类型枚举
public enum NotifyType
{
Temperature,
Humidity,
WindSpeed
}
// 发布者类
public class DynamicWeatherStation
{
// 按通知类型存储对应的观察者动作
private Dictionary<NotifyType, List<Action<object>>> _handlers = new Dictionary<NotifyType, List<Action<object>>>();
// 订阅指定类型的通知
public void Subscribe(NotifyType type, Action<object> handler)
{
if (!_handlers.ContainsKey(type))
{
_handlers[type] = new List<Action<object>>();
}
_handlers[type].Add(handler);
}
// 取消订阅指定类型的通知
public void Unsubscribe(NotifyType type, Action<object> handler)
{
if (_handlers.ContainsKey(type))
{
_handlers[type].Remove(handler);
}
}
// 发布指定类型的通知
public void Publish(NotifyType type, object data)
{
if (_handlers.ContainsKey(type))
{
foreach (var handler in _handlers[type])
{
handler(data);
}
}
}
}
class Program
{
static void Main()
{
DynamicWeatherStation station = new DynamicWeatherStation();
// 订阅温度通知
station.Subscribe(NotifyType.Temperature, (data) =>
{
Console.WriteLine($"温度观察者收到:{data}℃");
});
// 订阅湿度通知
station.Subscribe(NotifyType.Humidity, (data) =>
{
Console.WriteLine($"湿度观察者收到:{data}%");
});
// 发布通知
station.Publish(NotifyType.Temperature, 25.5f);
station.Publish(NotifyType.Humidity, 60.2f);
}
}不同实现方式的适用场景
以上三种另类实现各有适用场景,可以根据实际需求选择:
- 事件委托实现适合简单的内部模块通信,代码量少,上手快,不需要额外定义接口
- IObservable和IObserver实现适合需要和其他.NET响应式组件对接的场景,符合规范,扩展性强
- 泛型字典动态订阅适合需要按类型分发通知的复杂场景,支持灵活增删不同类别的观察者
这些实现都遵循观察者模式解耦发布者和订阅者的核心思想,跳出常规实现思路后,能更灵活地应对不同的开发需求。
C#观察者模式设计模式事件委托IObservableIObserver修改时间:2026-06-01 00:32:00