以下内容转载请注明来自"菩提树下的杨过(http://blog.sqlsky.com)"
应用概述:
某气象站通过传感器实时测量气温/湿度/压力等数据,要求设计一个系统,能让多种类型的公告栏自动更新这些数据(本例中有二类公告板:实时显示气温/温度公告板,动态统计最高/最低气温公告板)
解释:
应用观察者模式,把气温数据做为一个主题(也称为可观察者),让其它公告板当做观察者,通过订阅主题(也称通过观察"可观察者")来得知最新的信息(当然,观察者们也可以方便的退订,从而停止自动更新)
又一设计原则:
为了交互对象之间的松耦合设计而努力。
观察者接口
Code
1using System;
2using System.Collections.Generic;
3using System.Linq;
4using System.Text;
5
6namespace WeatherForecast
7{
8 /**//// <summary>
9 /// 观察者接口
10 /// </summary>
11 public interface Observer
12 {
13 void Update(float temperature,float humidity,float pressure);//用来更新各类公告板数据
14 }
15}
1using System;
2using System.Collections.Generic;
3using System.Linq;
4using System.Text;
5
6namespace WeatherForecast
7{
8 /**//// <summary>
9 /// 观察者接口
10 /// </summary>
11 public interface Observer
12 {
13 void Update(float temperature,float humidity,float pressure);//用来更新各类公告板数据
14 }
15}
公告板显示接口
Code
1using System;
2using System.Collections.Generic;
3using System.Linq;
4using System.Text;
5
6namespace WeatherForecast
7{
8 /**//// <summary>
9 /// 公告板"显示"功能接口
10 /// </summary>
11 interface DisplayElement
12 {
13 void Display();
14
15 }
16}
1using System;
2using System.Collections.Generic;
3using System.Linq;
4using System.Text;
5
6namespace WeatherForecast
7{
8 /**//// <summary>
9 /// 公告板"显示"功能接口
10 /// </summary>
11 interface DisplayElement
12 {
13 void Display();
14
15 }
16}
主题接口
Code
1using System;
2using System.Collections.Generic;
3using System.Linq;
4using System.Text;
5
6namespace 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}
1using System;
2using System.Collections.Generic;
3using System.Linq;
4using System.Text;
5
6namespace 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
1using System;
2using System.Collections.Generic;
3using System.Collections;
4using System.Linq;
5using System.Text;
6
7namespace 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
1using System;
2using System.Collections.Generic;
3using System.Collections;
4using System.Linq;
5using System.Text;
6
7namespace 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
1using System;
2using System.Collections.Generic;
3using System.Linq;
4using System.Text;
5
6namespace 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
1using System;
2using System.Collections.Generic;
3using System.Linq;
4using System.Text;
5
6namespace 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
1using System;
2using System.Collections.Generic;
3using System.Linq;
4using System.Text;
5
6namespace 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}
1using System;
2using System.Collections.Generic;
3using System.Linq;
4using System.Text;
5
6namespace 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
1using System;
2using System.Collections.Generic;
3using System.Linq;
4using System.Text;
5
6namespace 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}
1using System;
2using System.Collections.Generic;
3using System.Linq;
4using System.Text;
5
6namespace 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%