以下内容转载请注明来自"菩提树下的杨过(http://blog.sqlsky.com)"
应用概述:
某气象站通过传感器实时测量气温/湿度/压力等数据,要求设计一个系统,能让多种类型的公告栏自动更新这些数据(本例中有二类公告板:实时显示气温/温度公告板,动态统计最高/最低气温公告板)
解释:
应用观察者模式,把气温数据做为一个主题(也称为可观察者),让其它公告板当做观察者,通过订阅主题(也称通过观察"可观察者")来得知最新的信息(当然,观察者们也可以方便的退订,从而停止自动更新)
又一设计原则:
为了交互对象之间的松耦合设计而努力。
观察者接口

Code
1
using System;
2
using System.Collections.Generic;
3
using System.Linq;
4
using System.Text;
5
6
namespace WeatherForecast
7

{
8
/**//// <summary>
9
/// 观察者接口
10
/// </summary>
11
public interface Observer
12
{
13
void Update(float temperature,float humidity,float pressure);//用来更新各类公告板数据
14
}
15
}
公告板显示接口

Code
1
using System;
2
using System.Collections.Generic;
3
using System.Linq;
4
using System.Text;
5
6
namespace WeatherForecast
7

{
8
/**//// <summary>
9
/// 公告板"显示"功能接口
10
/// </summary>
11
interface DisplayElement
12
{
13
void Display();
14
15
}
16
}
主题接口

Code
1
using System;
2
using System.Collections.Generic;
3
using System.Linq;
4
using System.Text;
5
6
namespace WeatherForecast
7

{
8
/**//// <summary>
9
/// "主题"(也称为"被观察者")接口
10
/// </summary>
11
public interface Subject
12
{
13
void RegisterObserver(Observer o);
14
void RemoveObserver(Observer o);
15
void NotifyObservers();
16
17
}
18
}
真正的气象数据"主题"

Code
1
using System;
2
using System.Collections.Generic;
3
using System.Collections;
4
using System.Linq;
5
using System.Text;
6
7
namespace WeatherForecast
8

{
9
/**//// <summary>
10
/// 实现"主题"接口的气象数据类
11
/// </summary>
12
public class WeatherData:Subject
13
{
14
private ArrayList observers;//订阅本主题的观察者列表
15
private float temperature;
16
private float humidity;
17
private float pressure;
18
19
public WeatherData()
20
{
21
observers = new ArrayList();
22
}
23
24
/**//// <summary>
25
/// 注册观察者
26
/// </summary>
27
/// <param name="o"></param>
28
public void RegisterObserver(Observer o)
29
{
30
observers.Add(o);
31
}
32
33
/**//// <summary>
34
/// 取消观察者
35
/// </summary>
36
/// <param name="o"></param>
37
public void RemoveObserver(Observer o)
38
{
39
if (observers.Contains(o))
40
{
41
observers.Remove(o);
42
}
43
}
44
45
/**//// <summary>
46
/// 通知所有观察者
47
/// </summary>
48
public void NotifyObservers()
49
{
50
for (int i = 0; i < observers.Count; i++)
51
{
52
(observers[i] as Observer).Update(temperature, humidity, pressure);
53
}
54
}
55
56
/**//// <summary>
57
/// 当数据变化时,该方法自动被调用(实际应用中由硬件自动控制)
58
/// </summary>
59
public void MeasurementsChanged()
60
{
61
NotifyObservers();
62
}
63
64
/**//// <summary>
65
/// 设置气温/温度/压力(实际应用中,这些由数据探测器自动采集并自动设置)
66
/// </summary>
67
/// <param name="temperature"></param>
68
/// <param name="humidity"></param>
69
/// <param name="pressure"></param>
70
public void SetMeasurements(float temperature, float humidity, float pressure)
71
{
72
this.temperature = temperature;
73
this.humidity = humidity;
74
this.pressure = pressure;
75
MeasurementsChanged();//因为测试环境中,没有硬件环境,只能手动模拟调用
76
}
77
}
78
}
79
观察者之"实时气温/湿度公告板"

Code
1
using System;
2
using System.Collections.Generic;
3
using System.Linq;
4
using System.Text;
5
6
namespace WeatherForecast
7

{
8
/**//// <summary>
9
/// 实时气温/湿度公告板
10
/// </summary>
11
public class CurrentConditionDisplay:Observer,DisplayElement
12
{
13
private float temperature;
14
private float humidity;
15
private Subject weatherData;
16
17
public CurrentConditionDisplay(Subject weatherData)
18
{
19
this.weatherData = weatherData;
20
weatherData.RegisterObserver(this);
21
}
22
23
public void Update(float temperature, float humidity, float pressure)
24
{
25
this.temperature = temperature;
26
this.humidity = humidity;
27
Display();
28
}
29
30
public void Display()
31
{
32
Console.WriteLine("当前:气温" + temperature + "度,湿度" + humidity + "%");
33
}
34
}
35
}
36
观察者之"动态统计最高/最低气温公告板"

Code
1
using System;
2
using System.Collections.Generic;
3
using System.Linq;
4
using System.Text;
5
6
namespace WeatherForecast
7

{
8
/**//// <summary>
9
/// 动态统计最高/最低气温公告板
10
/// </summary>
11
public class StatisticDisplay:Observer,DisplayElement
12
{
13
private float temperature;
14
private float humidity;
15
private float maxTemperature;
16
private float minTemperature;
17
private Subject weatherData;
18
19
public StatisticDisplay(Subject weatherData)
20
{
21
this.weatherData = weatherData;
22
weatherData.RegisterObserver(this);
23
//将下列变量初始化一个不可能达到的值
24
temperature = -99999;
25
maxTemperature = -99999;
26
minTemperature = 99999;
27
}
28
29
public void Update(float temperature, float humidity, float pressure)
30
{
31
this.temperature = temperature;
32
this.humidity = humidity;
33
34
if (maxTemperature == -99999)
{ maxTemperature = temperature; }
35
if (minTemperature == 99999)
{ minTemperature = temperature; }
36
37
maxTemperature = maxTemperature > temperature ? maxTemperature : temperature;
38
minTemperature = minTemperature > temperature ? temperature : minTemperature;
39
40
Display();
41
}
42
43
public void Display()
44
{
45
Console.WriteLine("统计:最高气温 " + maxTemperature + "度 ,最低气温 " + minTemperature + "度\n");
46
}
47
48
}
49
}
最终测试:

Code
1
using System;
2
using System.Collections.Generic;
3
using System.Linq;
4
using System.Text;
5
6
namespace WeatherForecast
7

{
8
class Program
9
{
10
static void Main(string[] args)
11
{
12
WeatherData weatherData = new WeatherData();
13
14
CurrentConditionDisplay currentDisplay = new CurrentConditionDisplay(weatherData);
15
StatisticDisplay statisticDisplay = new StatisticDisplay(weatherData);
16
17
weatherData.SetMeasurements(23, 15, 20);
18
weatherData.SetMeasurements(28, 12, 25);
19
weatherData.SetMeasurements(30, 14, 23);
20
weatherData.SetMeasurements(25, 20, 35);
21
22
weatherData.RemoveObserver(statisticDisplay);//取消"statisticDisplay"的主题订阅
23
24
weatherData.SetMeasurements(18, 22, 33);
25
26
Console.Read();
27
28
}
29
}
30
}
运行结果:
当前:气温23度,湿度15%
统计:最高气温 23度 ,最低气温 23度
当前:气温28度,湿度12%
统计:最高气温 28度 ,最低气温 23度
当前:气温30度,湿度14%
统计:最高气温 30度 ,最低气温 23度
当前:气温25度,湿度20%
统计:最高气温 30度 ,最低气温 23度
当前:气温18度,湿度22%