当前位置: 首页 > news >正文

C# 设计模式--观察者模式 (Observer Pattern)

定义

观察者模式是一种行为设计模式,它定义了对象之间的一对多依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知并自动更新。观察者模式的核心在于解耦主题(被观察者)和观察者之间的依赖关系。

正确写法

假设我们有一个天气预报系统,当天气变化时,需要通知多个订阅者(如手机应用、网站等)。

using System;
using System.Collections.Generic;// 被观察者接口
public interface ISubject
{void RegisterObserver(IObserver observer);void RemoveObserver(IObserver observer);void NotifyObservers();
}// 观察者接口
public interface IObserver
{void Update(string weatherInfo);
}// 具体被观察者
public class WeatherStation : ISubject
{private List<IObserver> observers = new List<IObserver>();private string weatherInfo;public void SetWeatherInfo(string info){this.weatherInfo = info;NotifyObservers();}public void RegisterObserver(IObserver observer){observers.Add(observer);}public void RemoveObserver(IObserver observer){observers.Remove(observer);}public void NotifyObservers(){foreach (var observer in observers){observer.Update(weatherInfo);}}
}// 具体观察者
public class MobileApp : IObserver
{public void Update(string weatherInfo){Console.WriteLine($"Mobile App received: {weatherInfo}");}
}public class Website : IObserver
{public void Update(string weatherInfo){Console.WriteLine($"Website received: {weatherInfo}");}
}// 客户端代码
class Program
{static void Main(string[] args){WeatherStation weatherStation = new WeatherStation();IObserver mobileApp = new MobileApp();IObserver website = new Website();weatherStation.RegisterObserver(mobileApp);weatherStation.RegisterObserver(website);weatherStation.SetWeatherInfo("Sunny and warm");weatherStation.RemoveObserver(mobileApp);weatherStation.SetWeatherInfo("Cloudy with a chance of rain");}
}

类图:

ISubject
+void RegisterObserver(IObserver observer)
+void RemoveObserver(IObserver observer)
+void NotifyObservers()
IObserver
+void Update(string weatherInfo)
WeatherStation
-List observers
-string weatherInfo
+void SetWeatherInfo(string info)
+void RegisterObserver(IObserver observer)
+void RemoveObserver(IObserver observer)
+void NotifyObservers()
MobileApp
+void Update(string weatherInfo)
Website
+void Update(string weatherInfo)
Program
+static void Main(string[] args)

解释

  1. 被观察者接口 (ISubject):定义了注册、移除和通知观察者的方法。
  2. 观察者接口 (IObserver):定义了更新方法,当被观察者状态改变时,观察者会收到通知。
  3. 具体被观察者 (WeatherStation):实现了 ISubject 接口,管理观察者的注册、移除和通知。
  4. 具体观察者 (MobileAppWebsite):实现了 IObserver 接口,接收被观察者的通知并进行相应的处理。
  5. 客户端代码 (Program):创建了 WeatherStation 实例,并注册了 MobileAppWebsite 作为观察者。通过调用 SetWeatherInfo 方法改变天气信息,触发观察者的更新方法。之后移除 MobileApp 观察者,并再次改变天气信息,验证观察者机制。

用途

  1. 解耦主题和观察者:观察者模式使得主题和观察者之间的依赖关系变得松散,主题不需要知道观察者的具体实现。
  2. 动态注册和注销:观察者可以动态地注册和注销,使得系统更加灵活。
  3. 事件驱动:适用于事件驱动的系统,当某个事件发生时,可以通知多个观察者进行相应的处理。

优点

  1. 解耦:主题和观察者之间的依赖关系被解耦,使得代码更加灵活和可维护。
  2. 扩展性:增加新的观察者时,不需要修改主题的代码,符合开闭原则。
  3. 动态性:观察者可以动态地注册和注销,使得系统更加灵活。

缺点

  1. 性能问题:如果观察者数量较多,通知所有观察者可能会导致性能问题。
  2. 内存泄漏:如果观察者没有正确注销,可能会导致内存泄漏。
  3. 调试困难:由于观察者模式涉及多个对象之间的交互,调试时可能会比较困难。

适用场景

  1. 事件驱动系统:当需要在某个事件发生时通知多个对象时。
  2. 解耦对象:当需要解耦主题和观察者之间的依赖关系时。
  3. 动态注册和注销:当观察者需要动态地注册和注销时。
    实际开发中的应用

1. 消息通知系统

假设我们正在开发一个消息通知系统,当用户发布新消息时,需要通知多个订阅者(如邮件、短信、推送通知等)。

using System;
using System.Collections.Generic;// 被观察者接口
public interface IMessagePublisher
{void RegisterSubscriber(IMessageSubscriber subscriber);void UnregisterSubscriber(IMessageSubscriber subscriber);void NotifySubscribers(string message);
}// 观察者接口
public interface IMessageSubscriber
{void OnMessageReceived(string message);
}// 具体被观察者
public class MessagePublisher : IMessagePublisher
{private List<IMessageSubscriber> subscribers = new List<IMessageSubscriber>();public void PublishMessage(string message){NotifySubscribers(message);}public void RegisterSubscriber(IMessageSubscriber subscriber){subscribers.Add(subscriber);}public void UnregisterSubscriber(IMessageSubscriber subscriber){subscribers.Remove(subscriber);}public void NotifySubscribers(string message){foreach (var subscriber in subscribers){subscriber.OnMessageReceived(message);}}
}// 具体观察者
public class EmailSubscriber : IMessageSubscriber
{public void OnMessageReceived(string message){Console.WriteLine($"Email received: {message}");}
}public class SMS Subscriber : IMessageSubscriber
{public void OnMessageReceived(string message){Console.WriteLine($"SMS received: {message}");}
}public class PushNotificationSubscriber : IMessageSubscriber
{public void OnMessageReceived(string message){Console.WriteLine($"Push notification received: {message}");}
}// 客户端代码
class Program
{static void Main(string[] args){MessagePublisher publisher = new MessagePublisher();IMessageSubscriber emailSubscriber = new EmailSubscriber();IMessageSubscriber smsSubscriber = new SMS Subscriber();IMessageSubscriber pushNotificationSubscriber = new PushNotificationSubscriber();publisher.RegisterSubscriber(emailSubscriber);publisher.RegisterSubscriber(smsSubscriber);publisher.RegisterSubscriber(pushNotificationSubscriber);publisher.PublishMessage("New message: Hello, world!");publisher.UnregisterSubscriber(emailSubscriber);publisher.PublishMessage("Another message: Goodbye, world!");}
}

2. 股票市场监控

假设我们正在开发一个股票市场监控系统,当股票价格发生变化时,需要通知多个订阅者(如投资者、分析师等)。


```csharp
using System;
using System.Collections.Generic;// 被观察者接口
public interface IStockMarket
{void RegisterInvestor(IInvestor investor);void UnregisterInvestor(IInvestor investor);void NotifyInvestors(string stockInfo);
}// 观察者接口
public interface IInvestor
{void OnStockPriceChange(string stockInfo);
}// 具体被观察者
public class StockMarket : IStockMarket
{private List<IInvestor> investors = new List<IInvestor>();public void UpdateStockPrice(string stockInfo){NotifyInvestors(stockInfo);}public void RegisterInvestor(IInvestor investor){investors.Add(investor);}public void UnregisterInvestor(IInvestor investor){investors.Remove(investor);}public void NotifyInvestors(string stockInfo){foreach (var investor in investors){investor.OnStockPriceChange(stockInfo);}}
}// 具体观察者
public class IndividualInvestor : IInvestor
{public void OnStockPriceChange(string stockInfo){Console.WriteLine($"Individual Investor received: {stockInfo}");}
}public class InstitutionalInvestor : IInvestor
{public void OnStockPriceChange(string stockInfo){Console.WriteLine($"Institutional Investor received: {stockInfo}");}
}public class Analyst : IInvestor
{public void OnStockPriceChange(string stockInfo){Console.WriteLine($"Analyst received: {stockInfo}");}
}// 客户端代码
class Program
{static void Main(string[] args){StockMarket market = new StockMarket();IInvestor individualInvestor = new IndividualInvestor();IInvestor institutionalInvestor = new InstitutionalInvestor();IInvestor analyst = new Analyst();market.RegisterInvestor(individualInvestor);market.RegisterInvestor(institutionalInvestor);market.RegisterInvestor(analyst);market.UpdateStockPrice("Apple stock price increased by 5%");market.UnregisterInvestor(individualInvestor);market.UpdateStockPrice("Google stock price decreased by 2%");}
}

总结

观察者模式通过定义对象之间的一对多依赖关系,使得当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知并自动更新。虽然它可能会带来一些性能和调试上的问题,但在需要解耦主题和观察者、支持动态注册和注销的场景中,观察者模式能够显著提高代码的可维护性和扩展性。

http://www.lryc.cn/news/498856.html

相关文章:

  • 【开发语言】层次状态机(HSM)介绍
  • 03-13、SpringCloud Alibaba第十三章,升级篇,服务降级、熔断和限流Sentinel
  • 【k8s 深入学习之 event 聚合】event count累记聚合(采用 Patch),Message 聚合形成聚合 event(采用Create)
  • leetcode104.二叉树的最大深度
  • 蓝桥杯2117砍竹子(简单易懂 包看包会版)
  • LCD与lvgl
  • SpringBoot 赋能:精铸超稳会员制医疗预约系统,夯实就医数据根基
  • android studio 读写文件操作(应用场景二)
  • 小尺寸低功耗蓝牙模块在光伏清扫机器人上的应用
  • 防火墙有什么作用
  • MongoDB-BSON 协议与类型
  • 学习threejs,使用VideoTexture实现视频Video更新纹理
  • 怎么获取键值对的键的数值?
  • 数据结构排序算法详解
  • 在Linux设置postgresql开机自启动,创建一个文件 postgresql-15.service
  • 【kafka】消息队列的认识,Kafka与RabbitMQ的简单对比
  • ProjectSend 身份认证绕过漏洞复现(CVE-2024-11680)
  • Android笔记(三十四):onCreate执行Handler.post在onResume后才能执行?
  • 关闭模组的IP过滤功能
  • 算法分析与设计复习笔记
  • vue-amap 高德地图
  • Numpy基础练习
  • 一番赏小程序定制开发,打造全新抽赏体验平台
  • 【前端】将vue的方法挂载到window上供全局使用,也方便跟原生js做交互
  • Oracle查询优化:高效实现仅查询前10条记录的方法与实践
  • go语言编译问题
  • mobi文件转成pdf
  • MobaXterm解决中文显示乱码问题
  • 西门子 SINAMICS G120 变频器借助 ProfiNet 转 EtherCAT 实现与汇川 H5U 通讯实例
  • 流媒体之linux下离线部署FFmpeg 和 SRS