编辑
2025-11-28
C#
00

目录

🤔 为什么传统的监控系统难以维护?
紧耦合带来的痛点
🎯 观察者模式:解耦的艺术
核心设计思想
🔧 实战方案:工业传感器监控系统
1️⃣ 接口设计:定义通信协议
2️⃣ 传感器类:智能的数据源
3️⃣ 监控界面:优雅的观察者实现
4️⃣ 数据模拟:真实的工业环境
🎨 UI设计:工业级的用户体验
现代化配色方案
响应式布局设计
🚀 高级扩展:让系统更智能
多观察者协同工作
条件通知优化
💎 实战经验总结
三个"收藏级"代码模板
🎯 总结与思考

作为一名在工业软件领域摸爬滚打多年的老程序员,我发现很多开发者对观察者模式的理解往往停留在理论层面。最近在为某大型制造企业开发设备监控系统时,我深刻体会到了观察者模式在实际项目中的强大威力。想象一下:当生产线上的温度传感器数值异常时,监控大屏、报警系统、数据库记录模块都能第一时间收到通知并作出响应,这种松耦合的设计让系统既稳定又易于扩展。

今天就来分享一套完整的工业监控系统实现方案,帮你彻底掌握观察者模式的实战应用。

🤔 为什么传统的监控系统难以维护?

紧耦合带来的痛点

在没有使用观察者模式之前,我们通常会这样写代码:

C#
// ❌ 传统的紧耦合写法 public class Sensor { private MonitorPanel panel; private AlarmSystem alarmSystem; private DatabaseLogger logger; public void UpdateValue(double newValue) { this.value = newValue; // 直接调用各个模块 panel.UpdateDisplay(this.name, newValue); if(newValue > maxValue) alarmSystem.TriggerAlarm(this.name, newValue); logger.LogData(this.name, newValue); } }

这种写法存在明显问题:

  • 维护噩梦:每次新增监控模块都要修改Sensor类
  • 测试困难:无法独立测试各个组件
  • 扩展性差:系统规模越大,耦合越严重

🎯 观察者模式:解耦的艺术

核心设计思想

观察者模式通过定义一对多的依赖关系,让多个观察者对象同时监听某一个主题对象,当主题状态发生变化时,所有观察者都会收到通知。

image.png

🔧 实战方案:工业传感器监控系统

1️⃣ 接口设计:定义通信协议

C#
// 观察者接口 public interface IObserver { void Update(string sensorName, double value, DateTime timestamp, string status); } // 主题接口 public interface ISubject { void Attach(IObserver observer); void Detach(IObserver observer); void Notify(); }

设计要点

  • Update方法参数包含完整的传感器信息
  • 接口职责单一,便于后续扩展

2️⃣ 传感器类:智能的数据源

C#
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace AppObserverIndustrialMonitoringSystem { // <summary> /// 工业传感器类 - 主题实现 /// </summary> public class Sensor : ISubject { private List<IObserver> _observers; private string _name; private double _value; private DateTime _timestamp; private string _unit; private double _minValue; private double _maxValue; private string _location; public string Name => _name; public double Value => _value; public DateTime Timestamp => _timestamp; public string Unit => _unit; public double MinValue => _minValue; public double MaxValue => _maxValue; public string Location => _location; public Sensor(string name, string unit, double minValue, double maxValue, string location) { _observers = new List<IObserver>(); _name = name; _unit = unit; _minValue = minValue; _maxValue = maxValue; _location = location; _value = (minValue + maxValue) / 2; _timestamp = DateTime.Now; } public void Attach(IObserver observer) { if (!_observers.Contains(observer)) _observers.Add(observer); } public void Detach(IObserver observer) { _observers.Remove(observer); } public void Notify() { string status = GetStatus(); foreach (IObserver observer in _observers) { observer.Update(_name, _value, _timestamp, status); } } public void SetValue(double value) { _value = Math.Round(value, 2); _timestamp = DateTime.Now; Notify(); } private string GetStatus() { if (_value < _minValue) return "偏低"; if (_value > _maxValue) return "偏高"; return "正常"; } public bool IsNormal() { return _value >= _minValue && _value <= _maxValue; } } }

💡 实战技巧

  • 使用Contains检查避免重复添加观察者
  • SetValue方法中自动调用Notify(),确保数据一致性
  • 状态判断逻辑封装成私有方法,便于维护

3️⃣ 监控界面:优雅的观察者实现

C#
public partial class FrmMainMonitor : Form, IObserver { private List<Sensor> _sensors; private DataTable _sensorDataTable; private Random _random = new Random(); public void Update(string sensorName, double value, DateTime timestamp, string status) { // 跨线程调用处理 if (InvokeRequired) { Invoke(new Action<string, double, DateTime, string>(Update), sensorName, value, timestamp, status); return; } UpdateSensorDisplay(sensorName, value, timestamp, status); } private void UpdateSensorDisplay(string sensorName, double value, DateTime timestamp, string status) { // 更新DataGridView数据 foreach (DataRow row in _sensorDataTable.Rows) { if (row["传感器名称"].ToString() == sensorName) { row["当前值"] = value.ToString("F2"); row["状态"] = status; row["更新时间"] = timestamp.ToString("HH:mm:ss"); break; } } // 根据状态设置行颜色 UpdateRowColor(sensorName, status); // 异常时添加报警 if (status != "正常") { AddAlert(sensorName, value, status, timestamp); } } }

⚠️ 关键注意点

  • 线程安全:使用InvokeRequired处理跨线程UI更新
  • 性能优化:只更新变化的数据行,避免全表刷新
  • 用户体验:异常状态用颜色区分,提升可读性

4️⃣ 数据模拟:真实的工业环境

C#
private void SimulateSensorValue(Sensor sensor) { double range = sensor.MaxValue - sensor.MinValue; double baseValue = sensor.MinValue + range * 0.5; // 基准值 double variation = range * 0.3 * (_random.NextDouble() - 0.5); // ±15%波动 double newValue = baseValue + variation; // 15%概率产生异常值(模拟真实故障场景) if (_random.NextDouble() < 0.15) { if (_random.NextDouble() < 0.5) newValue = sensor.MinValue - range * 0.1; // 低于正常值 else newValue = sensor.MaxValue + range * 0.1; // 高于正常值 } sensor.SetValue(Math.Max(0, newValue)); }

image.png

🎨 UI设计:工业级的用户体验

现代化配色方案

C#
// 状态颜色定义 Color normalColor = Color.FromArgb(46, 204, 113); // 绿色-正常 Color warningColor = Color.FromArgb(241, 196, 15); // 黄色-警告 Color errorColor = Color.FromArgb(231, 76, 60); // 红色-异常 Color primaryColor = Color.FromArgb(52, 152, 219); // 蓝色-主题

响应式布局设计

使用TableLayoutPanel实现自适应布局,确保在不同分辨率下都有良好的显示效果:

C#
// 主布局:60% 数据区 + 20% 控制区 + 20% 报警区 tlpMain.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 60F)); tlpMain.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 20F)); tlpMain.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 20F));

🚀 高级扩展:让系统更智能

多观察者协同工作

C#
// 轻松添加新的监控模块 var temperatureSensor = new Sensor("锅炉温度", "°C", 80, 120, "A区锅炉房"); // 一个传感器可以有多个观察者 temperatureSensor.Attach(mainMonitorForm); // 主界面 temperatureSensor.Attach(alarmSystem); // 报警系统 temperatureSensor.Attach(dataLogger); // 数据记录 temperatureSensor.Attach(cloudUploader); // 云端上传

条件通知优化

C#
public class SmartSensor : Sensor { private double _lastNotifyValue; private DateTime _lastNotifyTime; public override void Notify() { // 只在值变化超过阈值或时间间隔足够时才通知 if (Math.Abs(_value - _lastNotifyValue) > 0.1 || DateTime.Now.Subtract(_lastNotifyTime).TotalSeconds > 5) { base.Notify(); _lastNotifyValue = _value; _lastNotifyTime = DateTime.Now; } } }

💎 实战经验总结

三个"收藏级"代码模板

  1. 线程安全的观察者更新
C#
public void Update(object data) { if (InvokeRequired) { Invoke(new Action<object>(Update), data); return; } // 实际更新逻辑 }
  1. 防重复订阅
C#
public void Attach(IObserver observer) { if (!_observers.Contains(observer)) _observers.Add(observer); }
  1. 异常安全的通知机制
C#
public void Notify() { var observersCopy = new List<IObserver>(_observers); foreach (var observer in observersCopy) { try { observer.Update(/* 参数 */); } catch (Exception ex) { // 记录日志,但不影响其他观察者 Console.WriteLine($"Observer update failed: {ex.Message}"); } } }

🎯 总结与思考

通过这个完整的工业监控系统案例,我们掌握了观察者模式的三个核心要点:

  1. 解耦设计:传感器与监控界面完全分离,各司其职
  2. 扩展性强:新增监控模块只需实现IObserver接口
  3. 实用性高:结合WinForms和多线程,解决实际开发问题

观察者模式不仅仅是一个设计模式,更是一种编程思维。在实际项目中,它能帮我们构建更加灵活、可维护的系统架构。

你在项目中遇到过哪些需要用观察者模式解决的场景? 或者在实现过程中碰到了什么技术难题?欢迎在评论区分享你的经验,让我们一起交流学习!

如果这篇文章对你有帮助,请转发给更多需要的同行,让更多C#开发者受益!


相关信息

通过网盘分享的文件:AppObserverIndustrialMonitoringSystem.zip 链接: https://pan.baidu.com/s/11TNypox6TPHTQFm2PLkJ9Q?pwd=88rp 提取码: 88rp --来自百度网盘超级会员v9的分享

本文作者:技术老小子

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!