气象站将为我们提供温度、湿度和压力的数据,其中有四家天气预报软件公司进行了订阅,它们根据天气数据提供不同的天气服务。在本例中,四家公司要求气象局提供统一接口,并能实时数据更新。
输入格式:
输入第一行给出一个正整数n(n⩽10)表示数据更新的批次。随后n行,每行给出3个实数(温度、湿度和气压),其间以半角逗号分隔。
输出格式:
输出n次四家气象软件的输出。
输入样例: 3
80.0,65.0,30.4
82.0,70.0,29.2
78.0,90.0,29.2
输出样例:
现状: 80F度和65% 湿度
平均/最高/最低温度 = 80/80/80
预测: 气温正在上升 热指数 82.95535
现状: 82F度和70% 湿度
平均/最高/最低温度 = 81/82/80
预测: 气温正变得凉爽
热指数86.90123
现状: 78F度和90% 湿度
平均/最高/最低温度 = 80/82/78
预测: 气温没有变化
热指数 83.64967
当对象间存在一对多关系时,则使用观察者模式(ObserverPattern)。比如,当一个对象被修改时,则会自动通知它的依赖对象。观察者模式属于行为型模式。
观察者模式的主要角色如下。
- 抽象主题(Subject)角色:也叫抽象目标类,它提供了一个用于保存观察者对象的聚集类和增加、删除观察者对象的方法,以及通知所有观察者的抽象方法。
- 具体主题(Concrete Subject)角色:也叫具体目标类,它实现抽象目标中的通知方法,当具体主题的内部状态发生改变时,通知所有注册过的观察者对象。
- 抽象观察者(Observer)角色:它是一个抽象类或接口,它包含了一个更新自己的抽象方法,当接到具体主题的更改通知时被调用。
- 具体观察者(Concrete Observer)角色:实现抽象观察者中定义的抽象方法,以便在得到目标的更改通知时更新自身的状态。
一个对象状态改变给其他对象通知的问题,而且要考虑到易用和低耦合,保证高度的协作。
杂志订阅,杂志是主题,观察者是订阅者。当出版新杂志时候,这个事件会自动通知所有的订阅者。
定义一个主题类接口,所有的被观察者都要实现该接口
interface ISubject
{
void RegisterObserver(IObserver o);//注册观察者
void RemoveObserver(IObserver o);//注销观察者
void notifyObservers();///数据发生变化时,通知观察者
}
定义一个观察者接口,所有的观察者都需要实现该接口的Update方法
interface IObserver
{
void Update(float temp, float humidity, float pressure);
}
interface IDisplayElement
{
void display();
}
主题接口的实现类
class WeatherData : ISubject
{
private float temperature;//温度
private float humidity;//湿度
private float pressure;//压力
private List<IObserver> observers;//观察者列表,用List来存储所有的观察者
public float Temperature { get { return temperature; } }
public float Humidity { get { return humidity; } }
public float Pressure { get { return pressure; } }
public WeatherData()
{
observers = new List<IObserver>();
}
public void RegisterObserver(IObserver o)
{
observers.Add(o);//添加观察者
}
public void RemoveObserver(IObserver o)
{
int i = observers.IndexOf(o);
observers.RemoveAt(i);//去除观察者
}
public void notifyObservers()
{
//当主题内容发生变化时,循环遍历所有观察者做出通知改变
foreach(IObserver o in observers)
{
o.Update(temperature, humidity, pressure);
}
}
参数内容变化时,调用该方法(这是本次任务要实现当输入的数据发生变化时,对应观察者所得到的内容发生改变的关键)
public void setMeasurements(string temperature, string humidity, string pressure)
{
float temp;
float.TryParse(temperature, out temp);
this.temperature = temp;
float.TryParse(humidity, out temp);
this.humidity = temp;
float.TryParse(pressure, out temp);
this.pressure = temp;
//当输入的数据发生变化时,每发生一次数据的改变
//就调用measurementsChanged()-->实际调用 notifyObservers()
//通知所加入主题类的所有观察者做出相对应的变化
measurementsChanged();
}
public void measurementsChanged()
{
notifyObservers();
}
CurrentConditionsDisplay 观察者
class CurrentConditionsDisplay : IObserver, IDisplayElement
{
private float temperature;
private float humidity;
public void Update(float temperature, float humidity, float pressure)
{
this.temperature = temperature;
this.humidity = humidity;
display();
}
public void display()
{
Console.WriteLine("现状: " + temperature + "F度和" + humidity + "% 湿度");
}
}
ForecastDisplay 观察者
class ForecastDisplay : IObserver, IDisplayElement
{
private float currentPressure = 29.92f;
private float lastPressure;
public void Update(float temp, float humidity, float pressure)
{
lastPressure = currentPressure;
currentPressure = pressure;
display();
}
public void display()
{
Console.Write("预测: ");
if (currentPressure > lastPressure) { Console.Write("气温正在上升\n"); }
else if (currentPressure == lastPressure) { Console.Write("气温没有变化\n"); }
else if (currentPressure < lastPressure) { Console.Write("气温正变得凉爽\n"); }
}
}
HeatIndexDisplay观察者
class HeatIndexDisplay : IObserver, IDisplayElement
{
float heatIndex = 0.0f;
public void Update(float t, float rh, float pressure)
{
heatIndex = computeHeatIndex(t, rh);
display();
}
public void display()
{
Console.WriteLine("热指数 " + heatIndex);
}
private float computeHeatIndex(float t, float rh)
{
float index = (float)((16.923 + (0.185212 * t) + (5.37941 * rh) - (0.100254 * t * rh)
+ (0.00941695 * (t * t)) + (0.00728898 * (rh * rh))
+ (0.000345372 * (t * t * rh)) - (0.000814971 * (t * rh * rh)) +
(0.0000102102 * (t * t * rh * rh)) - (0.000038646 * (t * t * t)) + (0.0000291583 *
(rh * rh * rh)) + (0.00000142721 * (t * t * t * rh)) +
(0.000000197483 * (t * rh * rh * rh)) - (0.0000000218429 * (t * t * t * rh * rh)) +
0.000000000843296 * (t * t * rh * rh * rh)) -
(0.0000000000481975 * (t * t * t * rh * rh * rh)));
return index;
}
}
StatisticsDisplay 观察者
class StatisticsDisplay : IObserver, IDisplayElement
{
private float maxTemp = 0.0f;
private float minTemp = 200;
private float tempSum = 0.0f;
private int numReadings;
public void display()
{
Console.WriteLine("平均/最高/最低温度 = " + (tempSum / numReadings) + "/" + maxTemp + "/" + minTemp);
}
public void Update(float temp, float humidity, float pressure)
{
tempSum += temp;
numReadings++;
if (temp > maxTemp)
{
maxTemp = temp;
}
if (temp < minTemp)
{
minTemp = temp;
}
display();
}
}
客户端实现
对于实现本次任务的要求,客户端的实现还是不可少的,不过一定要把问题理清逻辑后在动手!!!!
/**
我们按如下步骤来实现:
1、new一个主题
2、new 四个观察者
3、注册4个观察者
4、重复n次改变数据,观察者内容变化n次
*/
static void Main(string[] args)
{
int n=Convert.ToInt32(Console.ReadLine());
WeatherData data = new WeatherData();
data.RegisterObserver(new CurrentConditionsDisplay());
data.RegisterObserver(new StatisticsDisplay());
data.RegisterObserver(new ForecastDisplay());
data.RegisterObserver(new HeatIndexDisplay());
for(int i = 0; i < n; i++)
{
string str=Console.ReadLine();
string[] arr=str.Split(',');
data.setMeasurements(arr[0], arr[1], arr[2]);
}
}
本篇到此结束,欢迎小伙伴批评指正!!!