设计模式之观察者模式C#实现
说明:主要参考《Head First设计模式(中文版)》,使用C#代码实现。
代码:Github
1、观察者模式UML图
2、气象监测类图
3、气象监测代码(书中C#版)
3.1 Observer
1 2 3 4 | public interface IObserver { void Update( float temperature, float humidity, float pressure); } |
1 2 3 4 | public interface IDisplayElement { void Display(); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | public class CurrentConditionDisplay : IObserver, IDisplayElement { private readonly ISubject _weatherData; private float _temperature; private float _humidity; public CurrentConditionDisplay(ISubject weatherData) { _weatherData = weatherData; _weatherData?.RegisterObserver( this ); } public void Update( float temperature, float humidity, float pressure) { _temperature = temperature; _humidity = humidity; Display(); } public void Display() { Console.WriteLine($ "Current Conditions: {_temperature}F degress and {_humidity}% humidity" ); } } |
3.2 Subject
1 2 3 4 5 6 | public interface ISubject { void RegisterObserver(IObserver o); void RemoveObserver(IObserver o); void NotifyObservers(); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 | public class WeatherData : ISubject { //观察者列表 private readonly List<IObserver> _observerList; //天气数据 private float _temperature; private float _humidity; private float _pressure; public WeatherData() { _observerList = new List<IObserver>(); } /// <summary> /// 订阅观察者 /// </summary> /// <param name="o">观察者对象</param> public void RegisterObserver(IObserver o) { _observerList.Add(o); } /// <summary> /// 移除观察者 /// </summary> /// <param name="o">观察者对象</param> public void RemoveObserver(IObserver o) { if (_observerList.Contains(o)) { _observerList.Remove(o); } } /// <summary> /// 发布数据 /// </summary> public void NotifyObservers() { foreach ( var observer in _observerList) { observer.Update(_temperature, _humidity, _pressure); } } /// <summary> /// 数据发生改变 /// </summary> private void MeasurementChanged() { NotifyObservers(); } /// <summary> /// 更新数据 /// </summary> /// <param name="temperature">温度</param> /// <param name="humidity">湿度</param> /// <param name="pressure">气压</param> public void SetMeasurements( float temperature, float humidity, float pressure) { _temperature = temperature; _humidity = humidity; _pressure = pressure; MeasurementChanged(); } } |
3.3 测试代码
1 2 3 4 5 6 7 8 9 | private static void TestWeatherData() { var weatherData = new WeatherData(); var currentConditionDisplay = new CurrentConditionDisplay(weatherData); weatherData.SetMeasurements(80, 65, 30.4f); weatherData.SetMeasurements(82, 70, 29.2f); weatherData.SetMeasurements(78, 90, 29.2f); } |
4、使用C#中IObservable接口实现气象监测
4.1 辅助类/结构体
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | public struct WeatherMessage { public float Temperature { get ; set ; } public float Humidity { get ; set ; } public float Pressure { get ; set ; } } public class MessageUnknownException : Exception { internal MessageUnknownException() { } } |
4.2 IObserver具体实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | class CurrentConditionDisplayX : IObserver<WeatherMessage>, IDisplayElement { private IDisposable _unsubscribe; private float _temperature; private float _humidity; public void Subscribe(IObservable<WeatherMessage> provider) { if (provider != null ) { _unsubscribe = provider.Subscribe( this ); } } public void Unsubscribe() { _unsubscribe?.Dispose(); _unsubscribe = null ; } public void OnCompleted() { Console.WriteLine( "CurrentConditionDisplayX: OnCompleted" ); Unsubscribe(); } public void OnError(Exception error) { Console.WriteLine( "CurrentConditionDisplayX: OnError" ); } public void OnNext(WeatherMessage value) { _temperature = value.Temperature; _humidity = value.Humidity; Display(); } public void Display() { Console.WriteLine($ "Current Conditions: {_temperature}F degress and {_humidity}% humidity" ); } } |
4.3 IObservable具体实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 | public class WeatherDataX : IObservable<WeatherMessage> { private readonly List<IObserver<WeatherMessage>> _observerList; public WeatherDataX() { _observerList = new List<IObserver<WeatherMessage>>(); } /// <summary> /// 通知提供程序:某观察程序将要接收通知。 /// </summary> /// <param name="observer">要接收通知的对象。</param> /// <returns>使资源释放的观察程序的接口。</returns> public IDisposable Subscribe(IObserver<WeatherMessage> observer) { if (!_observerList.Contains(observer)) { _observerList.Add(observer); } return new Unsubcriber(_observerList, observer); } public void SetMeasurements(Nullable<WeatherMessage> message) { foreach ( var observer in _observerList) { if (!message.HasValue) { observer.OnError( new MessageUnknownException()); } else { observer.OnNext(message.Value); } } } public void EndTransmission() { foreach ( var observer in _observerList.ToArray()) { if (_observerList.Contains(observer)) { observer.OnCompleted(); } } _observerList.Clear(); } private class Unsubcriber : IDisposable { private List<IObserver<WeatherMessage>> _observerList; private IObserver<WeatherMessage> _observer; public Unsubcriber(List<IObserver<WeatherMessage>> observerList, IObserver<WeatherMessage> observer) { _observerList = observerList; _observer = observer; } public void Dispose() { if (_observerList != null && _observerList.Contains(_observer)) { _observerList.Remove(_observer); } } } } |
4.4 测试代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | private static void TestWeatherDataX() { var weatherData = new WeatherDataX(); var currentConditionDisplay = new CurrentConditionDisplayX(); currentConditionDisplay.Subscribe(weatherData); weatherData.SetMeasurements( new WeatherMessage() { Temperature = 80, Humidity = 65, Pressure = 30.4f }); weatherData.SetMeasurements( new WeatherMessage() { Temperature = 82, Humidity = 70, Pressure = 29.2f }); weatherData.SetMeasurements( new WeatherMessage() { Temperature = 78, Humidity = 90, Pressure = 29.2f }); weatherData.EndTransmission(); } |
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· .NET Core 托管堆内存泄露/CPU异常的常见思路
· DeepSeek “源神”启动!「GitHub 热点速览」
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· C# 集成 DeepSeek 模型实现 AI 私有化(本地部署与 API 调用教程)
· DeepSeek R1 简明指南:架构、训练、本地部署及硬件要求
· NetPad:一个.NET开源、跨平台的C#编辑器