观察者模式(Observer Pattern)
观察者模式(Observer Pattern)是一种行为设计模式,它定义了对象之间的一对多依赖关系,使得当一个对象的状态发生变化时,所有依赖于它的对象都会得到通知并自动更新。观察者模式又称为发布-订阅(Publish-Subscribe)模式。
关键点
- 主题(Subject):也称为被观察者或者可观察对象,维护一系列观察者对象,提供添加、删除和通知观察者的方法。
- 观察者(Observer):也称为订阅者,定义了接收和处理通知的接口。
- 具体主题(ConcreteSubject):实现了主题接口,负责维护观察者列表,并在状态变化时通知观察者。
- 具体观察者(ConcreteObserver):实现了观察者接口,实现接收和处理通知的具体行为。
示例
假设我们有一个简单的气象站应用,它能够实时获取温度、湿度和气压数据,并将这些数据显示在多个布告板上。我们可以使用观察者模式来实现气象数据和布告板之间的解耦。
1. 定义主题接口和观察者接口
csharp
// 主题接口
public interface ISubject
{
void RegisterObserver(IObserver observer);
void RemoveObserver(IObserver observer);
void NotifyObservers();
}
// 观察者接口
public interface IObserver
{
void Update(float temperature, float humidity, float pressure);
}
2. 实现具体主题和具体观察者类
csharp
using System;
using System.Collections.Generic;
// 具体主题类 - 气象数据
public class WeatherData : ISubject
{
private List<IObserver> observers;
private float temperature;
private float humidity;
private float pressure;
public WeatherData()
{
observers = new List<IObserver>();
}
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(temperature, humidity, pressure);
}
}
// 当气象数据更新时调用此方法
public void MeasurementsChanged()
{
NotifyObservers();
}
public void SetMeasurements(float temperature, float humidity, float pressure)
{
this.temperature = temperature;
this.humidity = humidity;
this.pressure = pressure;
MeasurementsChanged();
}
}
// 具体观察者类 - 布告板
public class Display : IObserver
{
private float temperature;
private float humidity;
private float pressure;
private WeatherData weatherData;
public Display(WeatherData weatherData)
{
this.weatherData = weatherData;
weatherData.RegisterObserver(this);
}
public void Update(float temperature, float humidity, float pressure)
{
this.temperature = temperature;
this.humidity = humidity;
this.pressure = pressure;
DisplayData();
}
public void DisplayData()
{
Console.WriteLine($"Current conditions: {temperature}F degrees and {humidity}% humidity");
}
}
3. 客户端代码
csharp
class Program
{
static void Main(string[] args)
{
WeatherData weatherData = new WeatherData();
// 创建布告板并注册到气象数据主题
Display display = new Display(weatherData);
// 模拟气象数据变化
weatherData.SetMeasurements(80, 65, 30.4f);
weatherData.SetMeasurements(82, 70, 29.2f);
}
}
解释
- 主题接口(ISubject):定义了主题对象需要实现的方法,包括注册、移除和通知观察者。
- 观察者接口(IObserver):定义了观察者对象需要实现的更新方法
Update
。 - 具体主题类(WeatherData):实现了主题接口,维护观察者列表,并在数据变化时通知所有观察者。
- 具体观察者类(Display):实现了观察者接口,接收并处理主题通知,实现了更新方法以更新布告板上的显示数据。
优点
- 松耦合:主题对象和观察者对象之间解耦,可以独立地改变和复用。
- 增强了模块的重用性:可以方便地增加和删除观察者,扩展性好。
- 支持广播通信:主题对象在状态改变时可以通知多个观察者。
缺点
- 观察者过多时可能会导致性能问题:如果观察者数量庞大或者观察者的更新操作较为复杂,可能会影响性能。
适用场景
- 对象间存在一对多的依赖关系:当一个对象的状态发生变化时,需要通知多个对象。
- 抽象模型有两个方面:一个依赖于另一个。
示例的现实应用
观察者模式在许多现实应用中都有应用:
- 事件处理系统:例如 GUI 应用程序中的事件处理机制。
- 消息中间件:例如 RabbitMQ、Kafka 等消息队列中的发布-订阅模型。
- 股票市场报价系统:例如股票价格变动时,通知所有相关的投资者和分析师。
通过使用观察者模式,可以实现对象之间的松耦合,提高系统的灵活性和可维护性。