《Head First 设计模式》之观察者模式——天气显示
观察者模式(Observer)
——在对象之间定义一对多的依赖,这样一来,当一个对象改变状态,依赖它的对象都会收到通知,并自动更新。
(出版者Subject+订阅者Observer=观察者模式)
- 特点:定义并维护对象之间的一对多关系
- 原则:为交互对象之间的松耦合设计而努力
- 示例(气象站类图)

三个接口:
public interface Subject{
public void registerObserver(Observer o);//注册观察者
public void removeOberver(Observer o);//删除观察者
public void notifyObserver();//通知观察者
}
public interface Observer{
public void update(float temp, float humidity, float pressure);
}
public interface DisplayElement{
public void display();
}
在WeatherData中实现主题接口:
public class WeatherData implements Subject{
private ArrayList observers;//记录观察者
private float temperature;
private float humidity;
private float pressure;
public WeatherData(){
observers = new ArrayList();
}
public void registerObserver(Observer o){//注册观察者
observers.add(o);
}
public void removeOberver(Observer o){//删除观察者
int i = observers.indexOf(o);
if(i >= 0){
observers.remove(0);
}
}
public void notifyObservers(){
for(int i = 0; i < observers.size(); i++){ //通知每一个观察者
Observer observer = (Observer)observers.get(i);
observer.update(temperature, humidity, pressure);
}
}
public void measurementsChanged(){
notifyObservers();
}
public void setMeasurements(float temp, float hum, float pre){
this.temperature = temp;
this.humidity = hum;
this.pressure = pre;
measurementsChanged();
}
}
实现CurrentConditionDisplay.java
public class CurrentConditionsDisplay implements Observer, DisplayElement{
private float temperature;
private float humidity;
private Subject weatherData;
public CurrentConditionsDisplay(Subject weatherData){//构造器需要weatherData对象作为注册之用
this.weatherData = weatherData;
weatherData.registerObserver(this);
}
public void update(float temp, float humidity, float pressure){
this.temperature = temp;
this.humidity = humidity;
display();
}
public void display(){
//输出
}
}
测试程序:
public class WeatherStation {
public static void main(String[] args) {
WeatherData weatherData = new WeatherData();//建立weatherData对象
CurrentConditionsDisplay currentDisplay = new CurrentConditionsDisplay(weatherData);
StatisticsDisplay statisticsDisplay = new StatisticsDisplay(weatherData);
ForecastDisplay forecastDisplay = new ForecastDisplay(weatherData);//将对象传给三个Observer,即add观察者
weatherData.setMeasurements(80, 65, 30.4f);
weatherData.setMeasurements(82, 70, 29.2f);
weatherData.setMeasurements(78, 90, 29.2f);
}
}
Java内置的观察者模式
上述示例实现信息由Subject “推送(push)” 至Observer,使用Java内置的观察者模式可以使用推(push)或拉(pull)的方式传送数据。不同的是WeatherData现在扩展自Observable类,并继承到一些add、delete、notify观察者的方法。
Subject -> java.util.Observable(类)
Observer -> java.util.Observer(接口)

Observable如何送出通知?
首先需要利用扩展 java.util.Observable 接口产生“可观察者”类(想要进行通知,则必须调用Observable类的setChanged方法,但是Observable的setChanged方法为protected,故只能使用继承来实现自己的主题对象),然后:
- 调用setChanged(),标记状态已经改变的事实;
- 调用notifyObservers()中的一个:notifyObservers() 或 notifyObservers(Object arg)
Observer如何接收通知?
update(Observable o, Object arg) :主题Observable作为第一变量,好让观察者知道是哪个主题通知它的。Object arg正是传入notifyObservers(Object arg)的数据对象,如果没有说明则为空。
若想push数据给观察者,可以把数据作数据对象传送给notifyObservers(Object arg)方法。否则,观察者就必须从可观察者对象中pull数据。如何拉数据?
WeatherData.java
public class WeatherData extends Observable{
private float temperature;
private float humidity;
private float pressure;
public WeatherData(){ } //无需建立观察者列表ArrayList了
public void measurementsChanged(){
setChanged();//状态已经改变
notifyObservers();//pull
}
public void setMeasurements(float temp, float hum, float pre){
this.temperature = temp;
this.humidity = hum;
this.pressure = pre;
measurementsChanged();
}
public float getTemperature(){
return temperature;
}
public float gethumidity(){
return humidity;
}
public float getpressure(){
return pressure;
}
}
CurrentConditionDisplay.java
public class CurrentConditionsDisplay implements Observer, DisplayElement{
private float temperature;
private float humidity;
Observable observable;
public CurrentConditionsDisplay(Observable observable){
this.observable = observable;
observable.addObserver(this);
}
public void update(Observable o, Object arg){
if(o instanceof WeatherData){
WeatherData weatherData = (WeatherData)o;
this.temperature = weatherData.getTemperature();
this.humidity = weatherData.gethumidity();
display();
}
}
public void display(){
//输出
}
}
notice:
- 不想推送的时候,不调用setChanged()方法即可
- 通知顺序不依赖于注册的顺序(即主题通知观察者的顺序与添加观察者的顺序无关)
- setChanged()方法的必要性:若无,则温度计读数每十分之一度就会更新,造成WeatherData对象持续不断地通知观察者。若希望温差达到半度时更新,就调用setChanged()。有更多的弹性,更适当地通知观察者。
使用Java自带的观察者模式的缺点:
- Observable是一个类,而不是一个接口,导致Observable类的扩展性不高,不如自己实现的观察者模式灵活
- Observable将某些方法保护了起来(setChanged()和clearChanged()为protected),这意味着除非继承自Observable,否则将有关键的方法不能调用。导致无法通过组合的方式使其它类获得Observable类的功能。违反了设计原则“多用组合,少用继承”。
《Head First 设计模式》之观察者模式——天气显示的更多相关文章
- [JS设计模式]:观察者模式(即发布-订阅者模式)(4)
简介 观察者模式又叫发布---订阅模式,它定义了对象间的一种一对多的关系,让多个观察者对象同时监听某一个主题对象,当一个对象发生改变时,所有依赖于它的对象都将得到通知. 举一个现实生活中的例子,例如小 ...
- 乐在其中设计模式(C#) - 观察者模式(Observer Pattern)
原文:乐在其中设计模式(C#) - 观察者模式(Observer Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 观察者模式(Observer Pattern) 作者:weba ...
- 设计模式之观察者模式(Observable与Observer)
设计模式之观察者模式(Observable与Observer) 好久没有写博客啦,之前看完了<设计模式之禅>也没有总结一下,现在回忆一下设计模式之观察者模式. 1.什么是观察者模式 简单情 ...
- 8.5 GOF设计模式四: 观察者模式Observer
GOF设计模式四: 观察者模式Observer 现实中遇到的问题 当有许多不同的客户都对同一数据源感兴趣,对相同的数据有不同的处理方式,该如 何解决?5.1 定义: 观察者模式 观察者模式 ...
- php 设计模式之观察者模式(订阅者模式)
php 设计模式之观察者模式 实例 没用设计模式的代码,这样的代码要是把最上面那部分也要符合要求加进来,就要修改代码,不符合宁增不改的原则 介绍 观察者模式定义对象的一对多依赖,这样一来,当一个对象改 ...
- 实践GoF的23种设计模式:观察者模式
摘要:当你需要监听某个状态的变更,且在状态变更时通知到监听者,用观察者模式吧. 本文分享自华为云社区<[Go实现]实践GoF的23种设计模式:观察者模式>,作者: 元闰子 . 简介 现在有 ...
- java_设计模式_观察者模式_Observer Pattern(2016-07-27)
看了好几篇文章,最终还是觉得<Head First 设计模式>举得例子比较符合观察者模式. 观察者模式概述: 观察者模式有时被称作发布/订阅模式,它定义了一种一对多的依赖关系,让多个观察者 ...
- Head First 设计模式之观察者模式(Observer Pattern)
前言: 这一节开始学习观察者模式,开始讲之前会先像第一节那样通过一个应用场景来引入该模式.具体场景为:气象站提供了一个WeatherData对象,该对象可以追踪获取天气的温度.气压.湿度信息,Weat ...
- 设计模式学习——观察者模式(Observer Pattern)
0. 前言 观察者模式在许多地方都能够用到,特别是作为MVC模式的一部分,在MVC中,模型(M):存放数据,视图(V):显示数据.当模型中的数据发生改变时,视图会得到通知,这是典型的观察者模式. 1. ...
随机推荐
- CentOS7下yum方式安装mysql5.6
在Centos7中用MariaDB代替了mysql数据库.所以在新安装MySQL前必须做好对系统的清理工作. 一.清理CentOS7下的MariaDB. [root@localhost ~]#rpm ...
- TCP/IP以及Socket对象基本
1 OSI七层模型概念介绍 物理层:数据以比特的方式进行传递,典型的设备是集线器.该层主要规定了设备的电压或者端口等等一些列物理层面上的规定 数据链路层:该层数据以帧的方式进行传递,主要是两个 ...
- day18-事务与连接池 4.事务特性
- hadoop2.6.0完全分布式部署
这里是hadoop最小的配置,也就是修改最少量的东西让hadoop跑起来. 系统是 Centos6.7 64位, hadoop是2.6.0,虚拟机是VMWare WorkStation 假设虚拟机启动 ...
- 如何将maven项目打包成可执行的jar
如何将maven项目打包成可执行的jar 分类: maven2010-12-17 10:18 10411人阅读 评论(2) 收藏 举报 jarmavenassemblyjava 方法一:将项目及所依赖 ...
- 滴水穿石 C#中多线程 委托的使用
什么是多线程?我们在建立以个C#项目时,往往会在Form1上添加控件,然后写代码,初 学者都是在重复这个过程,其实这个过程是单线程的,可以理解为只有“main”主线程,有 的时候往往需要同时测量多个东 ...
- c#入门学习-Action和Func的使用
我的理解就是:Action和Func就是官方声明好的代理using System; namespace funcActionDemo{ class MainClass { p ...
- php用百度地图API进行逆地址解析
<?php /** * 根据地理坐标获取国家.省份.城市,及周边数据类(利用百度Geocoding API实现) * 百度密钥获取方法:http://lbsyun.baidu.com/apico ...
- C#判断字符串是否是数字最简单的正则表达式
if (theStr!= null)//注意加非空判断,否则报错 { System.Text.RegularExpressions.Regex rex = new System.Text.Regula ...
- python numpy 判断ndarray 中是否有 nan
numpy.isnan(myarray).any() 下面讨论了哪一种方法的速度最快 reference: stackoverflow.com/questions/911871/detect-if-a ...