(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%

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏王磊的博客

Net连接mysql的公共Helper类MySqlHelper.cs带MySql.Data.dll下载

MySqlHelper.cs代码如下: using System; using System.Collections.Generic; using System...

5529
来自专栏领域驱动设计DDD实战进阶

领域驱动设计案例之实现业务3

2825
来自专栏Golang语言社区

厚土Go学习笔记 | 13. 用循环和函数 实现Sqrt(x)

利用前面学习的循环和函数,来实现 Sqrt(x)。并且与math.Sqrt(x)的结果做一下比较。 这个很有意思,所以,把中间不断带入的变化值都打印出来。 使用...

3556
来自专栏我和未来有约会

xml-rpc(2)-first demo_v2

[XmlRpcMethod("blogger.getUsersBlogs", Description = "获取博客信息")]         public B...

2055
来自专栏互联网开发者交流社区

STC-单片机控制系统

1873
来自专栏菩提树下的杨过

如何给已经有数据的DataTable动态增加一列并赋值

以前手写sql的时代,我们经常用DataTable,自从用Linq后,很少用DataTable这些原始的东东了,近日在开发中遇到一些特殊情况,用户要求临时在显示...

2629
来自专栏james大数据架构

Excel导入导出数据库01

主要分为两部份 1.Excel操作类 1 引入 2 using System.Data.OleDb; 3 using System.IO; 4 ...

25310
来自专栏C#

将DataTable转换成CSV文件

    DataTable用于在.net项目中,用于缓存数据,DataTable表示内存中数据的一个表。CSV文件最早用在简单的数据库里,由于其格式简单,...

2126
来自专栏阿炬.NET

SUI分页组件和avalon搞定ajax无刷新分页

3734
来自专栏菩提树下的杨过

.Net3.0中的自动属性(示例)

using System; namespace LinqDemo {     class Program     {         stat...

1988

扫码关注云+社区

领取腾讯云代金券