C#--观察者模式

文章目录

  • 编程要求
  • 输入/输出格式
  • 输入/输出样例
  • 相关知识
    • 概念
    • 模式的结构
    • 能解决的问题
    • 最贴切的案例
  • 任务实现

编程要求

  气象站将为我们提供温度、湿度和压力的数据,其中有四家天气预报软件公司进行了订阅,它们根据天气数据提供不同的天气服务。在本例中,四家公司要求气象局提供统一接口,并能实时数据更新。

C#--观察者模式_第1张图片

输入/输出格式

输入格式:
输入第一行给出一个正整数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)。比如,当一个对象被修改时,则会自动通知它的依赖对象。观察者模式属于行为型模式。

模式的结构

  观察者模式的主要角色如下。

  1. 抽象主题(Subject)角色:也叫抽象目标类,它提供了一个用于保存观察者对象的聚集类和增加、删除观察者对象的方法,以及通知所有观察者的抽象方法。
  2. 具体主题(Concrete Subject)角色:也叫具体目标类,它实现抽象目标中的通知方法,当具体主题的内部状态发生改变时,通知所有注册过的观察者对象。
  3. 抽象观察者(Observer)角色:它是一个抽象类或接口,它包含了一个更新自己的抽象方法,当接到具体主题的更改通知时被调用。
  4. 具体观察者(Concrete Observer)角色:实现抽象观察者中定义的抽象方法,以便在得到目标的更改通知时更新自身的状态。

            模式的结构类图如下
C#--观察者模式_第2张图片

能解决的问题

  一个对象状态改变给其他对象通知的问题,而且要考虑到易用和低耦合,保证高度的协作。

最贴切的案例

  杂志订阅,杂志是主题,观察者是订阅者。当出版新杂志时候,这个事件会自动通知所有的订阅者。

任务实现

定义一个主题类接口,所有的被观察者都要实现该接口

 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]);
            } 
        }

本篇到此结束,欢迎小伙伴批评指正!!!

你可能感兴趣的:(C#,c#,观察者模式,开发语言)