(Head First 设计模式)学习笔记(2) --观察者模式(气象站实例)

时间:2022-04-23
本文章向大家介绍(Head First 设计模式)学习笔记(2) --观察者模式(气象站实例),主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

应用概述: 某气象站通过传感器实时测量气温/湿度/压力等数据,要求设计一个系统,能让多种类型的公告栏自动更新这些数据(本例中有二类公告板:实时显示气温/温度公告板,动态统计最高/最低气温公告板)

解释: 应用观察者模式,把气温数据做为一个主题(也称为可观察者),让其它公告板当做观察者,通过订阅主题(也称通过观察"可观察者")来得知最新的信息(当然,观察者们也可以方便的退订,从而停止自动更新)

又一设计原则: 为了交互对象之间的松耦合设计而努力。

观察者接口

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);//用来更新各类公告板数据 

    }

}

公告板显示接口

Code

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;



namespace WeatherForecast

{

    /// <summary>

    /// 公告板"显示"功能接口

    /// </summary>

    interface DisplayElement

    {

        void Display();

        

    }

}

主题接口

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();



    }

}

真正的气象数据"主题"

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();//因为测试环境中,没有硬件环境,只能手动模拟调用

        }

    }

}

观察者之"实时气温/湿度公告板"

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 + "%");

        }

    }

}

观察者之"动态统计最高/最低气温公告板"

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");

        }



    }

}

最终测试:

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%