博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Head First设计模式之观察者模式(Observer Pattern)
阅读量:2231 次
发布时间:2019-05-09

本文共 5841 字,大约阅读时间需要 19 分钟。

前言:

     这一节開始学习观察者模式。開始讲之前会先像第一节那样通过一个应用场景来引入该模式。详细场景为:气象站提供了一个WeatherData对象。该对象能够追踪获取天气的温度、气压、湿度信息,WeatherData对象会随即更新三个布告板的显示:眼下状况(温度、湿度、气压)、气象统计和天气预报。

1.   基本需求:利用WeatherData对象获取数据、并更新三个布告板:眼下状况、气象统计和天气预报

WeatherData类图例如以下:

说明:

    GetTemperature()、GetHumidity()、GetPressure()分别用来获取天气温度、湿度气压。MeasurementsChanged()当气象測量更新此方法会被调用。

分析:

1.      能够通过WeatherData的Getter方法获取三个測量值:温度、湿度、气压

2.      气象測量更新时会调用MeasurementsChanged()方法

3.      须要实现三个天气数据布告板:“眼下状况”、“气象统计”、“天气预报”。一旦WeatherData測到新值,这些布告也立即更新

4.      此系统可扩展。能够随意的加入或者删除不论什么布告板。

实现:

public class WeatherData{   public void MeasurementsChanged()    {        float temp = GetTemperature();        float humidity = GetHumidity();        float pressure = GetPressure();         currentConditionDisplay.update(temp,humidity, pressure);        statisticsDisplay.update(temp,humidity, pressure);        forecastDisplay.update(temp, humidity,pressure);    }    //其它方法}

反思:

我们的这样的实现有何不妥?

结合我们第一节中的一些面向对象的原则,这样的实现方式会有例如以下问题:

l  针对详细实现编程,兴许新增或者删除布告板必须改动程序

l  未将改变的地方封装起来

这样的实现方式与面向对象的一些基本原则是相违背的。眼下临时是实现了用户的需求,可是在兴许不具备可扩展行。

2.   引入观察者模式

2.1 出版者+订阅者=观察者模式

出版者:就相当于“主题”(Subject),订阅者相当于“观察者”(Observer)

当出版者(主题)发行新的报纸的时候。全部的观察者(订阅者)就能够收到最新的报纸,同一时候。当新的观察者(订阅者)加入时,也能够收到最新的报纸。当观察者(订阅者)退订报纸后,就再也收不到新的报纸。

2.2 定义观察者模式

观察者模式定义了对象之间一对多依赖,这样一来,当一个对象状态改变时,它的全部依赖者都会收到通知并自己主动更新。

主题和观察者定义一对多的关系。

观察者依赖于此主题,仅仅要主题状态一有变化。观察者就会被通知,依据通知的风格。观察者可能因此新值而更新。

观察者模式:类图

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

松耦合的威力

当两个对象之间松耦合,它们依旧能够交互。可是不清楚彼此的细节。

观察者模式提供了一种对象设计,让主题和观察者之间松耦合。

说明:

1.      主题仅仅知道观察者实现了某个接口(IObserver接口)。不须要知道观察者是谁,或其它细节。

2.      不论什么时候都能够添加或者删除的观察者,主题唯一依赖的是一个实现了IObserver接口的对象列表。

3.      新的类型观察者出现时,主题代码不须要改动,仅仅须要在新类型里实现观察者接口,然后注冊为观察者就可以。

4.      能够独立的复用主题或观察者,由于二者松耦合。

5.      改变主题或者观察者。并不会影响还有一方。由于二者松耦合。

松耦合的设计之所以能让我们建立有弹性的OO系统,能够应对变化,是由于对象之间的相互依赖讲到了最低。

3.   利用观察者模式设计并实现气象站

3.1 设计气象站

类图:

3.2详细实现

3.2.1主题、观察者、显示接口
/// Description:对象、观察者、显示接口    ///     public interface ISubject    {        void RegisterObserver(IObserver o);//注冊观察者        void RemoveObserver(IObserver o);//删除观察者        void NotifyObervers();//通知观察者    }     public interface IObserver    {        void Update(float temp, float humidity,float pressure);    }     public interface IDisplayElement    {        void Display();}3.2.2 WeatherData类:注冊、删除、通知观察者/// Description:WeatherData 注冊、删除、通知观察者    ///     public class WeatherData:ISubject    {        private ArrayList observers;        private float temperature;        private float humidity;        private float pressure;         public WeatherData()        {            observers = new ArrayList();//初始化obervers。用来存储注冊的观察者        }         ///         /// 注冊观察者        ///         /// 
public void RegisterObserver(IObservero) { observers.Add(o); } ///
/// 删除观察者 /// ///
public void RemoveObserver(IObserver o) { int i = observers.IndexOf(o); if (i >= 0) observers.Remove(o); } ///
/// 通知观察者 /// public void NotifyObervers() { foreach (IObserver o in observers) { o.Update(temperature, humidity,pressure); } } ///
/// 当从气象站得到更新观測值时,通知观察者 /// public void MeasurementsChanged() { NotifyObervers(); } ///
/// /// ///
///
///
public void SetMeasurements(floattemperature, float humidity, float pressure) { this.temperature = temperature; this.humidity = humidity; this.pressure = pressure; MeasurementsChanged(); } }
3.2.3 布告板类。实现了IObserver、IDisplayElement接口

/// Description:创建布告板    ///     public classCurrentConditionsDisplay:IObserver,IDisplayElement    {        private float temperature;        private float humidity;        private ISubject weatherData;         public CurrentConditionsDisplay(ISubject 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("Currentcoditions: " + temperature + "F degress and " + humidity +"% humidity");        }    }

3.2.4 測试
WeatherStation.WeatherDataweatherData = new WeatherStation.WeatherData();WeatherStation.CurrentConditionsDisplaycurrentDisplay = new WeatherStation.CurrentConditionsDisplay(weatherData);weatherData.SetMeasurements(10,20, 30);

结果例如以下:

4.   Java内置的观察者模式

Java内置的观察者模式。很多功能都已经事先准备好了。甚至能够用推(push)或拉(pull)的方式传送数据。

使用java内置观察者模式实现气象站的OO设计类图,例如以下:

Java内置观察者模式与我们在3小节中明显的差异是WeatherData继承自Observable类。并集成了一些添加、删除、通知观察者的方法。

l  将对象变成观察者

首先还是要实现Observer(观察者)接口,其次调用Observable对象的addObserver()方法就可以。

l  可观察者(主题)送出通知

1.      先调用setChanged()方法。标记状态已经改变的事实。

2.      调用notifyObservers()方法(该方法有2个,随意一个皆可):notifyObservers()或notifyObservers(Object arg)

l  观察者接收通知

观察者实现了Observer的接口,方法签名例如以下:

update(Observable o,Object arg)

第一个參数为主题本身,让观察者知道是哪个主题通知它的

第二个參数是传入notifyObservers()的数据对象

假设想用“推”的方式将数据给观察者,则能够把数据当做数据对象的方式传给notifyObservers(arg)

假设想用“拉”的方式将数据给观察者,则须要在update()中,通过WeatherData的getTemperature()等方法获取相应的气象值。

缺陷:

Java内置的观察者模式中Observable是一个类,你必须设计一个类去继承它。假设某类同样时具有Observable类和还有一个超类的行为,就无法实现。由于java不支持多继承。

同一时候也限制了Observable的复用能力。

同一时候,Observable API将setChanged()方法保护了起来,除非继承自Observable类,否则无法创建Observable实例组合到自己的对象中。也违背了面向对象设计的第二个原则:多用组合。少用继承。

5.   总结

OO原则:

封装变化

多用组合,少用继承

针对接口编程,不针对实现编程

对交互对象之间的松耦合设计而努力(新的OO原则,松耦合的设计更有弹性。更能应对变化)

OO模式:

观察者模式—在对象之间定义一对多的依赖。这样一来,当一个对象改变状态。依赖它的对象都会收到通知,并自己主动更新。

转载于:https://www.cnblogs.com/ljbguanli/p/7307680.html

你可能感兴趣的文章
Leetcode C++《热题 Hot 100-48》406.根据身高重建队列
查看>>
《kubernetes权威指南·第四版》第二章:kubernetes安装配置指南
查看>>
Leetcode C++《热题 Hot 100-49》399.除法求值
查看>>
Leetcode C++《热题 Hot 100-51》152. 乘积最大子序列
查看>>
Leetcode C++ 《第181场周赛-1》 5364. 按既定顺序创建目标数组
查看>>
Leetcode C++ 《第181场周赛-2》 1390. 四因数
查看>>
阿里云《云原生》公开课笔记 第一章 云原生启蒙
查看>>
阿里云《云原生》公开课笔记 第二章 容器基本概念
查看>>
阿里云《云原生》公开课笔记 第三章 kubernetes核心概念
查看>>
阿里云《云原生》公开课笔记 第四章 理解Pod和容器设计模式
查看>>
阿里云《云原生》公开课笔记 第五章 应用编排与管理
查看>>
阿里云《云原生》公开课笔记 第六章 应用编排与管理:Deployment
查看>>
阿里云《云原生》公开课笔记 第七章 应用编排与管理:Job和DaemonSet
查看>>
阿里云《云原生》公开课笔记 第八章 应用配置管理
查看>>
阿里云《云原生》公开课笔记 第九章 应用存储和持久化数据卷:核心知识
查看>>
linux系统 阿里云源
查看>>
国内外helm源记录
查看>>
牛客网题目1:最大数
查看>>
散落人间知识点记录one
查看>>
Leetcode C++ 随手刷 547.朋友圈
查看>>