(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%
- js中数组(Array)的排序(sort)注意事项
- 双机热备工作模式及高内聚低耦合架构解释
- linux下拷贝命令中的文件过滤操作记录
- 关于智慧城市的十大反思(上)
- scrollTop与offsetTop研究
- JQuery笔记(四) 通用选择的尝试
- Docker容器学习梳理--基础环境安装
- Javascript:模仿淘宝的信用评价
- 好米有好价! 两枚4字母域名均以五位数交易
- Docker容器学习梳理--Volume数据卷使用
- 菜单常用:复位全部并设置某个项的样式
- Mysql更换MyISAM存储引擎为Innodb的操作记录
- 比特币分叉倒计时,糖果福利又来了
- 执行git push出现"Everything up-to-date"
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Android碎片fragment实现静态加载的实例代码
- android异步消息机制 源码层面彻底解析(1)
- /undefinedcss/modules/layer/default/layer.css?v=3.1.1找不到的问题
- Android实现渐变启动页和带有指示器的引导页
- the input device is not a TTY. If you are using mintty, try prefixing the comma
- 【STM32F407】第13章 RL-TCPnet V7.X之创建多个TCP客户端
- RecyclerView实现列表倒计时
- wsl设置默认账户为root(ubuntu18.04)
- LeetCode No.14 最长公共前缀
- android异步消息机制 从源码层面解析(2)
- beego解决跨域问题:options请求、axios post请求跨域问题
- Android ListView列表实现倒计时
- [-Flutter 自组篇-] 蛛网图+绘制+动画实践
- Kotlin类型系统竟如此简单
- 以人为本 | Android 11 的消息通知