观察者模式

观察者模式 (Observer Pattern)

观察者模式定义了对象之间的一对多依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知并自动更新。这种模式通常用于实现事件处理系统。

关键角色:

  1. Subject(主题) 也称为被观察者,它维护着一个观察者列表,并提供注册、取消注册以及通知观察者的方法。
  2. Observer(观察者) 是具体观察者的接口,定义了一个 Update方法来接收主题状态改变的通知。

以下是为了解释概念而使用接口解释具体机制的代码,实际不会使用这种实现方式,除非你用的是JAVA之类的比较原始的语言。它需要使用接口来定义主题和观察者的行为,适用于需要高度抽象和接口严格分离的情况,代码较为繁琐,但易于扩展。

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
// 观察者模式的主体接口
public interface ISubject
{
void RegisterObserver(IObserver observer);
void RemoveObserver(IObserver observer);
void NotifyObservers();
}
// 观察者接口
public interface IObserver
{
void Update(string message);
}
// 实现ISubject接口
public class WeatherData : ISubject
{
// 所有的观察者
private List<IObserver> observers = new List<IObserver>();
private string currentWeather;
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(currentWeather);
}
}
public void SetWeather(string weather)
{
this.currentWeather = weather;
NotifyObservers();
}
}
// 实现IObserver接口
public class CurrentConditionsDisplay : IObserver
{
public void Update(string message)
{
Console.WriteLine($"Current conditions display: {message}");
}
}

C#里这么写就太麻烦了,而且高度抽象需要的接口太多,我们有 delegateevent 可用

使用 event 实现观察者模式

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
// 定义一个委托,用于处理天气变化的通知
public delegate void WeatherChangedEventHandler(string message);
// 天气数据类
public class WeatherData
{
// 定义一个事件,当天气变化时触发
public event WeatherChangedEventHandler WeatherChanged;
// 当前天气状况
private string currentWeather;
// 设置天气状况,并通知观察者
public void SetWeather(string weather)
{
this.currentWeather = weather;
OnWeatherChanged(weather);
}
// 触发事件的方法
protected virtual void OnWeatherChanged(string message)
{
WeatherChanged?.Invoke(message);
}
}
// 当前天气状况显示类
public class CurrentConditionsDisplay
{
// 订阅天气变化事件
public CurrentConditionsDisplay(WeatherData weatherData)
{
weatherData.WeatherChanged += DisplayUpdate;
}
// 更新天气状况
private void DisplayUpdate(string message)
{
Console.WriteLine($"Current conditions display: {message}");
}
}

如果希望更懒,更伸手就来,则可以不自己定义 delegate,而直接使用C#提供的 EventHandler

使用 EventHandler

除了需要自定义一个事件参数类,继承自 EventArgs,用于封装发生变化的数据,这种方式直接使用了C#的事件处理机制,是更符合语言特性的实践方式。更加简洁,易于理解和使用。

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
public class WeatherChangedEventArgs : EventArgs 
{
public string CurrentWeather { get; set; }
public WeatherChangedEventArgs(string currentWeather)
{
CurrentWeather = currentWeather;
}
}
public class WeatherData
{
// 使用EventHandler<T>简化事件定义
public event EventHandler<WeatherChangedEventArgs> WeatherChanged;
private string currentWeather;
public void SetWeather(string weather)
{
this.currentWeather = weather;
// 触发事件,并传递包含新天气信息的事件参数
OnWeatherChanged(new WeatherChangedEventArgs(weather));
}
protected virtual void OnWeatherChanged(WeatherChangedEventArgs e)
{
WeatherChanged?.Invoke(this, e);
}
}
public class CurrentConditionsDisplay
{
public CurrentConditionsDisplay(WeatherData weatherData)
{
// 订阅WeatherChanged事件
weatherData.WeatherChanged += WeatherData_WeatherChanged;
}
private void WeatherData_WeatherChanged(object sender, WeatherChangedEventArgs e)
{
Console.WriteLine($"Current conditions display: {e.CurrentWeather}");
}
}

观察者模式
https://newztx.github.io/2024/08/11/观察者模式/
作者
Cranky Dove
发布于
2024年8月11日
许可协议