news 2026/5/29 7:05:17

我的实用设计模式之Observer模式

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
我的实用设计模式之Observer模式

于一直做监控程序的开发,对Observer模式的感受比较深,现在从一个例子入手,假如需求是实现一套手机告警监控系统,当一个智能手机接收到告警信息的时候需要通过不同的手段来通知用户,通知手段包括在LCD显示告警的图片和播放告警的声音。

从上图可以看到这个系统主要分三个类,WarningManager负责管理和产生告警,AudioManager负责播放声音,DisplayManager负责显示告警图片。WarningManager和AudioManager以及DisplayManager是composition的关系,所谓composition就是强耦合,WarningManager包含了AudioManager和DisplayManager的引用,AudioManager和DisplayManager为WarningManager的成员。

public sealed class Warning
{
public int Level{set; get;}
public int Type{set; get;}
}

public class AudioManager
{
public void HandleWarning(Warning warning)
{
Console.WriteLine("Play warning audio.");
}
}

public class DisplayManager
{
public void HandleWarning(Warning warning)
{
Console.WriteLine("Show warning picture.");
}
}

public class WarningManager
{
private AudioManager audioManager = new AudioManager();
private DisplayManager displayManager = new DisplayManager();

private void HandleWarning(Warning warning)
{
audioManager.HandleWarning(warning);
displayManager.HandleWarning(warning);
}
}

但是有一天客户想出一个新需求,告警不仅仅需要发声和显示,而且需要发短信。为了处理这个需求,实现一个新的类SMSManager来处理短信操作。但是我们发现问题出现了,WarningManager的功能对于这个新需求本来不需要任何的修改(因为告警的管理和生产过程没有任何改变),但是为了发送短信,不得不把SMSManager的引用作为新的properties。也就是说,每次这样类似需求的修改,WarningManager都要做出相应的修改,如下代码。

public class SMSManager
{
public void HandleWarning(Warning warning)
{
Console.WriteLine("Send out SMS.");
}
}

public class WarningManager
{
private AudioManager audioManager = new AudioManager();
private DisplayManager displayManager = new DisplayManager();
private SMSManager smsManager = new SMSManager();

private void HandleWarning(Warning warning)
{
audioManager.HandleWarning(warning);
displayManager.HandleWarning(warning);
smsManager.HandleWarning(warning);
}
}

软件设计和开发人员在设计阶段需要把当前需求以及将来的变化的需求考虑清楚,设计出可扩展性的系统,根据Open-Closed Principle ,应该把不变的需求(WarningManager)封装起来。同时适应变化的需求(不同的通知方式)。这样就引入了Observer模式来解决这一类问题。Observer模式可以广泛应用于消息通知系统,消息通知系统主要有两部分组成,一部分是消息源,另外一部分为消息处理类。消息源就如WarningManager,负责管理和产生消息。消息处理类就像AudioManager和DisplayManager那样,从消息源那里得到消息,然后进行处理。

上图为Observer模式通用实现,消息源抽象成Subject类而消息处理类抽象成Observer类。由于C#在语法层built-in了Observer模式(使用delegate和event),所以,在实现上大大的简化了。上述例子使用Observer的实现如下。

public sealed class Warning
{
public int Level{set; get;}
public int Type{set; get;}
}

public class AudioManager
{
public AudioManager()
{
WarningManager.WarningEvent += HandleWarning;
}

public void HandleWarning(Warning warning)
{
Console.WriteLine("Play warning audio.");
}
}

public class DisplayManager
{
public DisplayManager()
{
WarningManager.WarningEvent += HandleWarning;
}

public void HandleWarning(Warning warning)
{
Console.WriteLine("Show warning picture.");
}
}

public class SMSManager
{
public SMSManager()
{
WarningManager.WarningEvent += HandleWarning;
}

public void HandleWarning(Warning warning)
{
Console.WriteLine("Send out SMS.");
}
}

public sealed class WarningManager
{
public delegate void WarningEventHandler(Warning warning);
public static event WarningEventHandler WarningEvent;

private void Notify(Warning warning)
{
WarningEventHandler warningEvent = WarningEvent;
if (warningEvent != null)
{
warningEvent(warning);
}
}
}

从上图看,WarningManager不再需要保存消息处理类的引用了,也就是说客户想增加新的通知手段,WarningManager不需要进行任何的修改。WarningManager 定义一个event提供给各个消息处理类进行订阅。消息处理类订阅该消息WarningManager.WarningEvent += HandleWarning;每当有告警产生的时候,WarningManager可以通知到各个订阅消息的消息处理类。哪怕某天客户想增加新需求,例如当收到告警的时候发送email,系统只要增加EmailManager处理类,WarningManager不需要任何的修改。

Observer模式应用广泛消息通知系统,我认为MS之所以把Observer直接built-in到C#语法里面,是因为Observer广泛的使用在界面(Winform和Webform)用户动作的处理上,在Forms上对每一个控件的用户动作事件处理都是注册事件到一个处理函数。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/3/31 20:02:45

Laravel-Vue SPA测试策略:单元测试与功能测试全覆盖

Laravel-Vue SPA测试策略:单元测试与功能测试全覆盖 【免费下载链接】laravel-vue-spa A Laravel-Vue SPA starter kit. 项目地址: https://gitcode.com/gh_mirrors/la/laravel-vue-spa Laravel-Vue SPA是一个功能强大的单页应用开发框架,为确保应…

作者头像 李华
网站建设 2026/3/31 20:02:44

基于Dify平台快速构建MogFace-large人脸检测AI应用

基于Dify平台快速构建MogFace-large人脸检测AI应用 你有没有遇到过这样的场景?手头有一个性能强大的人脸检测模型,比如MogFace-large,想把它变成一个能对外提供服务的API,让网页或者手机App都能调用。但一想到要写后端服务、处理…

作者头像 李华
网站建设 2026/4/2 19:08:19

FPGA新手必看:Vivado 2023.1里用DDS IP核生成1MHz正弦波,附完整仿真代码

FPGA实战:从零构建1MHz正弦波生成器的Vivado全流程解析 刚拿到FPGA开发板时,我最想实现的第一个项目就是信号发生器。看着示波器上跳动的波形从自己编写的代码中产生,这种成就感无可替代。本文将带你用Xilinx Vivado 2023.1中的DDS IP核&…

作者头像 李华
网站建设 2026/3/31 19:59:30

Gemini 3.1镜像实战:用三层思考架构与多模态引擎解决视频内容生产

谷歌2026年初发布的Gemini 3.1 Pro,凭借可配置的三层思考架构(低/中/高推理深度)和集成Veo视频引擎、Lyria 3音频引擎的多模态能力,为实际业务问题提供了全新的解决范式。国内开发者和内容创作者可通过聚合平台RskAi(w…

作者头像 李华
网站建设 2026/3/31 19:58:51

eSearch屏幕截图工具实战指南:跨平台屏幕操作深度配置与性能优化

eSearch屏幕截图工具实战指南:跨平台屏幕操作深度配置与性能优化 【免费下载链接】eSearch 截屏 离线OCR 搜索翻译 以图搜图 贴图 录屏 万向滚动截屏 屏幕翻译 Screenshot Offline OCR Search Translate Search for picture Paste the picture on the screen Screen…

作者头像 李华