Observer 观察者模式
项目:气象监测系统
需求分析::此系统中三个部分是气象站(获取实际气象数据的物理装置)、WeatherData对象(追踪气象站的数据,并更新布告板)和布告板(显示目前天气状况给用户看)。
WeatherData对象知道如何跟物理气象站联系,以取得更新的数据。WeatherData对象会随机更新三个布告板的显示:目前状况(温度、湿度、气压)、气象统计和天气预报。
当WeatherData对象发生变化时,即刻更新数据并推送给三个布告板。因此WeatherData需要获得布告板的引用,在数据更新时发送给布告板。用代码说话:
首先设计2个接口:
1. Subject,包含3个方法:Register, Remove, NotifyObservers
2.Observer, 包含1个方法:Update
设计WeatherData,实现Subject。除此之外还需要获得布告板引用,添加字段observerList集合,以及温度、湿度、气压字段。还有设置天气属性的的方法SetMeasurements,
MeasurementsChanged方法,当设置天气属性时即调用改方法,然后通知注册的用户。
1 namespace ObserverPattern 2 { 3 public interface Subject 4 { 5 void RegisterObserver(Observer o); 6 void RemoveObserver(Observer o); 7 void NotifyObservers(); 8 } 9 }
1 namespace ObserverPattern 2 { 3 public interface Observer 4 { 5 void Update(float temp, float humidity, float pressure); 6 } 7 }
1 using System.Collections.Generic; 2 3 namespace ObserverPattern 4 { 5 public class WeatherData : Subject 6 { 7 private List<Observer> observerList = new List<Observer>(); 8 private float temperature; 9 private float humidity; 10 private float pressure; 11 12 public void NotifyObservers() 13 { 14 foreach (Observer o in observerList) 15 { 16 o.Update(temperature, humidity, pressure); 17 } 18 } 19 20 public void RegisterObserver(Observer o) 21 { 22 observerList.Add(o); 23 } 24 25 public void RemoveObserver(Observer o) 26 { 27 if(observerList.Contains(o)) 28 { 29 observerList.Remove(o); 30 } 31 32 } 33 /// <summary> 34 /// 设置温度、湿度、气压 35 /// </summary> 36 /// <param name="temperature">温度</param> 37 /// <param name="humidity">湿度</param> 38 /// <param name="pressure">气压</param> 39 public void SetMeasurements(float temperature, float humidity, float pressure) 40 { 41 this.temperature = temperature; 42 this.humidity = humidity; 43 this.pressure = pressure; 44 MeasurementsChanged(); 45 } 46 private void MeasurementsChanged( ) 47 { 48 NotifyObservers(); 49 } 50 } 51 }
接下来时设计3个布告板类,直接上代码:
1 using System; 2 3 namespace ObserverPattern 4 { 5 /// <summary> 6 /// 此布告板根据WeatherData对象显示当前观测值 7 /// </summary> 8 public class CurrentConditionsDisplay : Observer, DisplayElement 9 { 10 private float temperature; 11 private float humidity; 12 13 private Subject weatherData; 14 15 public CurrentConditionsDisplay() 16 { 17 18 } 19 public CurrentConditionsDisplay(Subject w) 20 { 21 weatherData = w; 22 weatherData.RegisterObserver(this); 23 } 24 /// <summary> 25 /// 把最近的温度和湿度显示出来 26 /// </summary> 27 public void Display() 28 { 29 Console.WriteLine("Current conditions:{0} F degress and {1} % humidity", temperature, humidity); 30 } 31 32 33 public void Update(float temp, float humidity, float pressure) 34 { 35 this.temperature = temp; 36 this.humidity = humidity; 37 Display(); 38 } 39 } 40 }
1 using System; 2 3 namespace ObserverPattern 4 { 5 /// <summary> 6 /// 此布告板根据气压计显示天气预报 7 /// </summary> 8 public class ForecastDisplay : Observer, DisplayElement 9 { 10 private WeatherData weatherData; 11 private float currentPressure = 29.92f; 12 private float lastPressure; 13 public ForecastDisplay() 14 { 15 16 } 17 public ForecastDisplay(WeatherData w) 18 { 19 weatherData = w; 20 w.RegisterObserver(this); 21 } 22 public void Display() 23 { 24 Console.Write("Forecast: "); 25 if(currentPressure > lastPressure) 26 { 27 Console.WriteLine("天气状况转良!"); 28 } 29 else if(currentPressure == lastPressure) 30 { 31 Console.WriteLine("气压没有变化"); 32 } 33 else 34 { 35 Console.WriteLine("注意天气变凉,雨水天气"); 36 } 37 } 38 39 40 41 public void Update(float temp, float humidity, float pressure) 42 { 43 lastPressure = currentPressure; 44 currentPressure = pressure; 45 Display(); 46 } 47 } 48 }
1 using System; 2 3 namespace ObserverPattern 4 { 5 /// <summary> 6 /// 此布告板跟踪最小、平均、最大的观测值,并显示它们 7 /// </summary> 8 public class StatisticsDisplay : Observer, DisplayElement 9 { 10 private WeatherData weatherData; 11 private float maxTemp = 0f; 12 private float minTemp = 200f; 13 private float tempSum = 0f; 14 private static int numReadings = 0; 15 public StatisticsDisplay(WeatherData w) 16 { 17 weatherData = w; 18 weatherData.RegisterObserver(this); 19 } 20 public StatisticsDisplay() 21 { 22 23 } 24 public void Display() 25 { 26 Console.WriteLine("Avg/Max/Min temperature = " + (tempSum / numReadings) 27 + "/" + maxTemp + "/" + minTemp); 28 } 29 30 31 32 public void Update(float temp, float humidity, float pressure) 33 { 34 tempSum += temp; 35 numReadings++; 36 if(temp > maxTemp) 37 { 38 maxTemp = temp; 39 } 40 if(temp < minTemp) 41 { 42 minTemp = temp; 43 } 44 Display(); 45 } 46 } 47 }
1 using System; 2 3 namespace ObserverPattern 4 { 5 class WeatherStation 6 { 7 static void Main(string[] args) 8 { 9 WeatherData weatherData = new WeatherData(); 10 CurrentConditionsDisplay currentDisplay = new CurrentConditionsDisplay(weatherData); 11 ForecastDisplay forecastDisplay = new ForecastDisplay(weatherData); 12 StatisticsDisplay statisticsDisplay = new StatisticsDisplay(weatherData); 13 //模拟气象测量 14 weatherData.SetMeasurements(80f, 65f, 30.4f); 15 weatherData.SetMeasurements(100f, 62f, 28.0f); 16 weatherData.SetMeasurements(86f, 72f, 26.3f); 17 Console.ReadKey(); 18 } 19 } 20 }
运行结果: