编程要求
气象站将为我们提供温度、湿度和压力的数据,其中有四家天气预报软件公司进行了订阅,它们根据天气数据提供不同的天气服务。在本例中,四家公司要求气象局提供统一接口,并能实时数据更新。请补全右侧代码区begin至end间的代码,不可修改原代码。
输入格式:
输入第一行给出一个正整数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
相关知识
概念
当对象间存在一对多关系时,则使用观察者模式(Observer Pattern)。比如,当一个对象被修改时,则会自动通知它的依赖对象。观察者模式属于行为型模式。
模式的结构
观察者模式的主要角色如下。
抽象主题(Subject)角色:也叫抽象目标类,它提供了一个用于保存观察者对象的聚集类和增加、删除观察者对象的方法,以及通知所有观察者的抽象方法。
具体主题(Concrete Subject)角色:也叫具体目标类,它实现抽象目标中的通知方法,当具体主题的内部状态发生改变时,通知所有注册过的观察者对象。
抽象观察者(Observer)角色:它是一个抽象类或接口,它包含了一个更新自己的抽象方法,当接到具体主题的更改通知时被调用。
具体观察者(Concrete Observer)角色:实现抽象观察者中定义的抽象方法,以便在得到目标的更改通知时更新自身的状态。
观察者模式的结构图如图 1 所示。
能解决的问题
一个对象状态改变给其他对象通知的问题,而且要考虑到易用和低耦合,保证高度的协作。
最贴切的案例
杂志订阅,杂志是主题,观察者是订阅者。当出版新杂志时候,这个事件会自动通知所有的订阅者。
代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace F1
{
class Program
{
static void Main(string[] args)
{
/********** Begin *********/
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]);
}
/********** End *********/
}
}
interface ISubject
{
void RegisterObserver(IObserver o);//注册观察者
void RemoveObserver(IObserver o);//注销观察者
void notifyObservers();///数据发生变化时,通知观察者
}
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)
{
/********** Begin *********/
observers.Add(o);
/********** End *********/
}
public void RemoveObserver(IObserver o)
{
int i = observers.IndexOf(o);
/********** Begin *********/
observers.RemoveAt(i);
/********** End *********/
}
public void notifyObservers()
{
/********** Begin *********/
foreach(IObserver o in observers)
o.Update(temperature, humidity, pressure);
/********** End *********/
}
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();
}
public void measurementsChanged()
{
notifyObservers();
}
}
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 + "% 湿度");
}
}
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"); }
}
}
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;
}
}
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();
}
}
}