应用概述: 某气象站通过传感器实时测量气温/湿度/压力等数据,要求设计一个系统,能让多种类型的公告栏自动更新这些数据(本例中有二类公告板:实时显示气温/温度公告板,动态统计最高/最低气温公告板)
解释: 应用观察者模式,把气温数据做为一个主题(也称为可观察者),让其它公告板当做观察者,通过订阅主题(也称通过观察"可观察者")来得知最新的信息(当然,观察者们也可以方便的退订,从而停止自动更新)
又一设计原则: 为了交互对象之间的松耦合设计而努力。
观察者接口
代码语言:javascript复制Code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace WeatherForecast
{
/// <summary>
/// 观察者接口
/// </summary>
public interface Observer
{
void Update(float temperature,float humidity,float pressure);//用来更新各类公告板数据
}
}
公告板显示接口
代码语言:javascript复制Code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace WeatherForecast
{
/// <summary>
/// 公告板"显示"功能接口
/// </summary>
interface DisplayElement
{
void Display();
}
}
主题接口
代码语言:javascript复制Code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace WeatherForecast
{
/// <summary>
/// "主题"(也称为"被观察者")接口
/// </summary>
public interface Subject
{
void RegisterObserver(Observer o);
void RemoveObserver(Observer o);
void NotifyObservers();
}
}
真正的气象数据"主题"
代码语言:javascript复制Code
using System;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using System.Text;
namespace WeatherForecast
{
/// <summary>
/// 实现"主题"接口的气象数据类
/// </summary>
public class WeatherData:Subject
{
private ArrayList observers;//订阅本主题的观察者列表
private float temperature;
private float humidity;
private float pressure;
public WeatherData()
{
observers = new ArrayList();
}
/// <summary>
/// 注册观察者
/// </summary>
/// <param name="o"></param>
public void RegisterObserver(Observer o)
{
observers.Add(o);
}
/// <summary>
/// 取消观察者
/// </summary>
/// <param name="o"></param>
public void RemoveObserver(Observer o)
{
if (observers.Contains(o))
{
observers.Remove(o);
}
}
/// <summary>
/// 通知所有观察者
/// </summary>
public void NotifyObservers()
{
for (int i = 0; i < observers.Count; i )
{
(observers[i] as Observer).Update(temperature, humidity, pressure);
}
}
/// <summary>
/// 当数据变化时,该方法自动被调用(实际应用中由硬件自动控制)
/// </summary>
public void MeasurementsChanged()
{
NotifyObservers();
}
/// <summary>
/// 设置气温/温度/压力(实际应用中,这些由数据探测器自动采集并自动设置)
/// </summary>
/// <param name="temperature"></param>
/// <param name="humidity"></param>
/// <param name="pressure"></param>
public void SetMeasurements(float temperature, float humidity, float pressure)
{
this.temperature = temperature;
this.humidity = humidity;
this.pressure = pressure;
MeasurementsChanged();//因为测试环境中,没有硬件环境,只能手动模拟调用
}
}
}
观察者之"实时气温/湿度公告板"
代码语言:javascript复制Code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace WeatherForecast
{
/// <summary>
/// 实时气温/湿度公告板
/// </summary>
public class CurrentConditionDisplay:Observer,DisplayElement
{
private float temperature;
private float humidity;
private Subject weatherData;
public CurrentConditionDisplay(Subject weatherData)
{
this.weatherData = weatherData;
weatherData.RegisterObserver(this);
}
public void Update(float temperature, float humidity, float pressure)
{
this.temperature = temperature;
this.humidity = humidity;
Display();
}
public void Display()
{
Console.WriteLine("当前:气温" temperature "度,湿度" humidity "%");
}
}
}
观察者之"动态统计最高/最低气温公告板"
代码语言:javascript复制Code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace WeatherForecast
{
/// <summary>
/// 动态统计最高/最低气温公告板
/// </summary>
public class StatisticDisplay:Observer,DisplayElement
{
private float temperature;
private float humidity;
private float maxTemperature;
private float minTemperature;
private Subject weatherData;
public StatisticDisplay(Subject weatherData)
{
this.weatherData = weatherData;
weatherData.RegisterObserver(this);
//将下列变量初始化一个不可能达到的值
temperature = -99999;
maxTemperature = -99999;
minTemperature = 99999;
}
public void Update(float temperature, float humidity, float pressure)
{
this.temperature = temperature;
this.humidity = humidity;
if (maxTemperature == -99999) { maxTemperature = temperature; }
if (minTemperature == 99999) { minTemperature = temperature; }
maxTemperature = maxTemperature > temperature ? maxTemperature : temperature;
minTemperature = minTemperature > temperature ? temperature : minTemperature;
Display();
}
public void Display()
{
Console.WriteLine("统计:最高气温 " maxTemperature "度 ,最低气温 " minTemperature "度n");
}
}
}
最终测试:
代码语言:javascript复制Code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace WeatherForecast
{
class Program
{
static void Main(string[] args)
{
WeatherData weatherData = new WeatherData();
CurrentConditionDisplay currentDisplay = new CurrentConditionDisplay(weatherData);
StatisticDisplay statisticDisplay = new StatisticDisplay(weatherData);
weatherData.SetMeasurements(23, 15, 20);
weatherData.SetMeasurements(28, 12, 25);
weatherData.SetMeasurements(30, 14, 23);
weatherData.SetMeasurements(25, 20, 35);
weatherData.RemoveObserver(statisticDisplay);//取消"statisticDisplay"的主题订阅
weatherData.SetMeasurements(18, 22, 33);
Console.Read();
}
}
}
运行结果: 当前:气温23度,湿度15% 统计:最高气温 23度 ,最低气温 23度
当前:气温28度,湿度12% 统计:最高气温 28度 ,最低气温 23度
当前:气温30度,湿度14% 统计:最高气温 30度 ,最低气温 23度
当前:气温25度,湿度20% 统计:最高气温 30度 ,最低气温 23度
当前:气温18度,湿度22%