转载: http://www.cnblogs.com/shitouer/archive/2011/09/02/2164048.html

Head First里边给出的场景是

客户需要这样一个App:一个WheatherData类可以从气象站获得气象信息(temperature, humidity, pressure and so on).一旦这些信息改变,就会更新气象站的三个公告板(CurrentConditionBulletin, StatisticsBulletin and ForecastBulletin, 另外,用户还可以随时增加/删除/更改自己的布告板)。

客户给出了WheatherData的类图:

结合以上描述和类图我们已知:

1. 由Getter可以或得气象信息

2. 一旦气象信息有改变,调用measurementsChanged()方法更新所有的布告板

3. 现在需要三个布告板

4. Customer可以定义自己的布告板

首先看一个不好的实现:

publicclass WeatherData {       publicvoid MeasurementsChanged(){floattemp = getTemperature(); floathumidity = getHumidity(); floatpressure = getPressure();currentConditionsDisplay.update(temp, humidity, pressure); statisticsDisplay.update(temp, humidity, pressure);forecastDisplay.update(temp, humidity, pressure);}
}
?

  为什么不好呢?可以从已经知道的几个设计原则入手:

1. 找出程序中变化的部分,将其与固定不变的部分隔离

在这个场景中,变化的是布告栏的类型和数量,在这个不好的例子中,我们改变布告栏的类型和数量,势必要修改WheatherData这个类。如何才能可以随意修改布告栏的数量和类型,却不用修改WheatherData类呢?

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

明显,statisticsDisplay,statisticsDisplay,forecastDisplay均是具体的实现的编程,如果以后我们增加修改布告栏,都必须修改这段程序。而且三个方法( update() )的名字和参数相同,一个统一的接口可行?

可以根据报纸订阅业务对观察者模式有一个简单的了解:

观察者模式类图:

Subject

主题接口,也即可观察者(Observable),对象使用此接口注册为观察者,或者把自己从观察着中删除。每个主题可以有多个观察者。

ConcreteSubject

一个具体主题实现了主题接口,除了注册和撤销之外,具体主题还实现了notifyObservers()方法,这个方法用来在主题状态改变时更行所有的观察者。具体主题也可能有设置和获取状态的方法。

Observer

所有潜在的观察者必须实现观察者接口,这个接口只有update()方法,当主题改变时,它被调用。

ConcreteObserver

具体的观察者可以是任何实现了Observer接口的类。观察者必须注册具体主题,一边接收更新。

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

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

观察者模式中,一对多的关系体现在哪里?

这个模式中,主题是具有状态的对象,并且可以控制这个状态,也就是说,是一个具有“状态”的主题。

另一方面,观察者使用这些状态,虽然这些状态并不属于他们。有多个观察者,依靠主题来告诉他们主题状态何时变了。

这就产生了一个关系,一个“主题”对多个“观察者”的关系

松耦合设计威力体现在哪里?

当两个对象松耦合,他们依然可以交互,但是不太清楚彼此的细节。观察者模式提供了一种对象设计,让主题和观察者松耦合。

下面我们根据观察者模式来画出开篇WheatherStation的类图

代码如下

  ISubject:
?
importorg.jpatterns.gof.ObserverPattern;@ObserverPattern(comment="ISubject: Interface of Observer Pattern"
)
publicinterface ISubject {voidregisterObserver(IObserver o);voiddeleteObserver(IObserver o);voidnotifyObservers();
}IObserver:
?
importorg.jpatterns.gof.ObserverPattern;@ObserverPattern(comment="IObserver: Interface of Observer Pattern"
)
publicinterface IObserver {voidupdate(floattemp, floathumidity, floatpressure);
}实现了ISubject接口的WheatherData:
?
importjava.util.ArrayList;importorg.jpatterns.gof.ObserverPattern;@ObserverPattern(comment = "WheatherData: Concrete Subject of Observer Pattern")
publicclass WheatherData implementsISubject {privateArrayList<IObserver> observers;privatefloat temperature;privatefloat humidity;privatefloat pressure;publicWheatherData() {this.observers = newArrayList<IObserver>();}@Overridepublicvoid registerObserver(IObserver o) {observers.add(o);}@Overridepublicvoid deleteObserver(IObserver o) {if(observers.indexOf(o) >= 0) {observers.remove(o);}}@Overridepublicvoid notifyObservers() {for(inti = 0; i < observers.size(); i++) {IObserver observer = observers.get(i);observer.update(temperature, humidity, pressure);}}publicvoid measurementsChanged() {this.notifyObservers();}publicvoid setMeasurements(floattemperature, floathumidity, floatpressure) {this.temperature = temperature;this.humidity = humidity;this.pressure = pressure;this.measurementsChanged();}
}实现了IObserver接口的一个Bulletin:
?
publicclass CurrentConditionsBulletin implementsIObserver, IDisplayElement {privatefloat temperature;privatefloat humidity;privateISubject wheatherData;publicCurrentConditionsBulletin(ISubject wheatherData) {this.wheatherData = wheatherData;wheatherData.registerObserver(this);}@Overridepublicvoid update(floattemp, floathumidity, floatpressure) {this.temperature = temp;this.humidity = humidity;this.display();}@Overridepublicvoid display() {System.out.println("Current Conditions: " + this.temperature+"F Degrees and " + this.humidity + "% Humidity");}
}创建气象站,将程序run起来:
?
publicclass WheatherStation {publicstatic void main(String[] args) {WheatherData wheatherData = newWheatherData();IObserver o1 = newCurrentConditionsBulletin(wheatherData);IObserver o2 = newStatisticsBulletin(wheatherData);IObserver o3 = newForecastBulletin(wheatherData);IObserver o4 = newCustomBulletin(wheatherData);//自定义的wheatherData2.setMeasurements(20,20,20);}}

  省略了好多注释啊,想好好理解,还是推荐去看HeadFirst吧,说实话,真本书真好!

其实在java中已经有内置的观察者模式。java.util中的Observable(类)和Observer(接口)。但是缺点不少,例如违反了:针对接口变成,而不是针对实现编程和多用组合少用继承两个原则,而且起nofify也依赖顺序。

观察者模式的要点:

观察者定义了对象之间一对多的关系。

主题用一个共同的接口来更新观察者。

观察者和可观察者之间用松耦合方式结合,可观察者不知道观察者的细节,只知道观察者实现了观察者接口。

使用此模式,可以从可观察者推或者拉数据。

有多个观察者时,不可以依赖特定的通知次序。

要注意java.util.Observable实现上带来的问题。

如果有必要的话,可以实现自己的Observable。

观察者模式的应用

观察者模式的优点

观察者和可观察者之间是抽象耦合

建立了一套完整的触发链

观察者模式的缺点

多级触发的效率问题

Java中消息的通知默认是顺序执行的,一个观察者卡壳,会影响整体的效率

观察者模式的使用场景

可拆分的关联行为场景

事件多级触发的场景

跨系统的消息交换场景

学习笔记 ---- 设计模式之观察者模式相关推荐

  1. Unity游戏框架学习笔记——03基于观察者模式的事件中心

    Unity游戏框架学习笔记--03基于观察者模式的事件中心 基于观察者模式的事件中心 一如既往指路牌:https://www.bilibili.com/video/BV1C441117wU?p=5. ...

  2. C++ 设计模式(可复用面向对象软件的基础)学习笔记——第五讲 观察者模式

    对于设计模式初学者来说,GoF的这本设计模式(可复用面向对象软件的基础)是有些难理解的,因此我先看了视频教程,附上教程链接网址https://www.bilibili.com/video/av5225 ...

  3. [学习笔记]设计模式之Command

    为方便读者,本文已添加至索引: 设计模式 学习笔记索引 写在前面 在上篇Chain of Responsibility(职责链)模式笔记中,我们学习了一种行为型设计模式.今天,我们继续这一主题,来学习 ...

  4. [学习笔记]设计模式之Decorator

    写在前面 为方便读者,本文已添加至索引: 设计模式 学习笔记索引 Decorator(装饰)模式,可以动态地给一个对象添加一些额外的职能.为了更好地理解这个模式,我们将时间线拉回Bridge模式笔记的 ...

  5. 【HeadFirst 设计模式学习笔记】2 观察者模式

    1.我们需要理解报社.订阅系统和订报人之间的关系,订报人通过订阅系统订报,一旦报社有新的报纸,订阅系统就会派人送或者邮寄给订报人新的报纸.然后,出版者+订阅者就是观察者模式,只不过名称不一样,主题(S ...

  6. [学习笔记]设计模式之Singleton

    写在前面 为方便读者,本文已添加至索引: 设计模式 魔法手札索引 在前几篇笔记中,我们有了解了部分对象创建型模式,包括Builder(建造者).Abstract Factory(抽象工厂)和Facto ...

  7. [学习笔记]设计模式[6]-{适配器模式外观模式}

    设计原则 最少知识原则:只和你的密友谈话 这个原则的意思是,在系统设计的过程中,不要让太多的类耦合在一起,免得对系统一部分的修改会影响到其他部分.在设计系统之前,应该首先注意对象与对象之间的交互关系, ...

  8. sheng的学习笔记-设计模式-代理模式

    原理图: 代理模式的定义:由于某些原因需要给某对象提供一个代理以控制对该对象的访问.这时,访问对象不适合或者不能直接引用目标对象,代理对象作为访问对象和目标对象之间的中介. 至少在以下集中情况下可以用 ...

  9. sheng的学习笔记-设计模式-单例模式

    转载文章:​​​​​​Java单例模式的5种实现方法_明朗晨光的专栏-CSDN博客_单例模式java​​​​​​ 饿汉 类加载的时候就创建了实例 优点:类加载的时候创建一次实例,避免了多线程同步问题 ...

最新文章

  1. 下拉菜单连动效果的一种用法
  2. jasmine.any(Function)
  3. oracle spring 分页查询,SpringJDBC 调用oracle 通用存储过程分页
  4. 静态变量加载时间,静态代码块加载时间
  5. 华为Mate 20 X(5G)评测:6199元的5G双模旗舰手机
  6. 单片机ADC采样算法----中位值平均滤波法
  7. 微软推出 “Edge 漏洞研究计划”,类似于谷歌的 Project Zero 项目
  8. 百度地图实现定位图标随手机方向变化而变化,即运用方向传感器
  9. 计算机重启 ie 被改,ie被修改怎么办 ie被修改的解决方法【详解】
  10. Netcdf4.4的安装过程(附netcdf4.1.3的安装过程)
  11. sapi 实现语音朗读
  12. 数字和ASII码之间的转换
  13. 常见嵌入式WEB服务器
  14. 【PHP】单词十以内的加法de多种解法
  15. python写一个飞花令程序
  16. linux系统旋转屏幕命令,Archlinux 实现屏幕旋转
  17. mosquitto 在 Windows 上的安装
  18. hihocoder1081
  19. Unity减少安装包的大小总结
  20. Codeforces Round #533(Div. 2) A.Salem and Sticks

热门文章

  1. Excel导入导出组件的设计
  2. TP/TCP/UDP
  3. 同步异步、阻塞非阻塞
  4. 推荐游戏玩家使用金山密保保护帐号安全
  5. 基于vue-cli3+typescript+element-ui搭建起来的后端管理平台框架(骨架)
  6. 全球最大电子展2018再度起航,镁客网在香港带你深度探讨人工智能
  7. python基本数据类型(一)-python3.0学习笔记
  8. java程序内存泄漏场景及预防
  9. (七)Oracle学习笔记—— 游标
  10. 《iOS应用开发指南——使用HTML5、CSS3和JavaScript》——第1章 变小的巨大影响1.1 移动魔力和掌上电脑...