作者:Grey

原文地址:http://www.cnblogs.com/greyzeng/p/5918205.html

模式名称

观察者模式(Observer Pattern)

需求

我们要通过WeatherData对象从物理气象站获取温度,湿度,气压数据,并且更新三个布告板的信息:

  • 目前状况(温度,湿度,气压)
  • 气象统计
  • 天气预报

解决方案

WeatherData类中,我们可以通过以下三个方法来获取测量值:

getTemperature() // 获取温度
getHumidity() // 获取湿度
getPressure() // 获取气压

当新的测量数据准备好以后,

measurementsChanged()

方法被调用

然后我们就可以更新三个布告板的数据了。

更多地,我们需要满足可扩展的要求,可以方便添加/删除布告板

一种实现:

public class WeatherData {
public void measurementsChanged() {
float temperature = getTemperature(); // 获取温度
float humidity = getHumidity() // 获取湿度
float pressure = getPressure() // 获取气压
currentConditionsDisplay.update(temperature, humidity, pressure); // 更新“目前状况”布告板
statisticsDisplay.update(temperature, humidity, pressure); // 更新“气象统计”布告板
forecastDisplay.update(temperature, humidity, pressure); // 更新“天气预报”布告板
}
}

这个模型类似于出版者和订阅者的关系,出版者发布了主题(气压,湿度,温度),订阅者订阅这些主题,等这些主题有新的内容的时候,会自动推送给订阅了这个主题的订阅者这里,这就是观察者模式,其中出版者被称为“主题”(Subject),订阅者被称为“观察者”(Observer)。

public interface Observer {
// 观察者根据传入的参数进行更新操作。
public void update(temperature, humidity, pressure);
}
public interface Subject {
void registerObserver(Observer o); // 注册观察者
void removeObserver(Observer o); // 移除观察者
void notifyObservers(); // 主题变化后,通知观察者
}

WeatherData需要实现主题接口

public class WeatherData implements Subject {
private ArrayList<Observer> observers; // 用来装需要订阅这个主题的观察者
private float temperature;
private float humidity;
private float pressure;
WeatherData() {
observers = new ArrayList<>();
}
@Override
public void registerObserver(Observer o) {
observers.add(o); // 订阅 } @Override
public void removeObserver(Observer o) {
if (null == observers || 0 == observers.size()) {
System.out.println("observers is null");
} else {
int i = observers.indexOf(o);
if (i >= 0) {
observers.remove(i); // 取消订阅
}
}
} @Override
public void notifyObservers() {
if (null == observers || 0 == observers.size()) {
System.out.println("observers is null");
} else {
for (Observer observer : observers) {
observer.update(temperature, humidity, pressure); // 更新每个观察者的状态
}
}
} public void setMeasurements(float temperature, float humidity, float pressure) {
// 当我们调用setMeasurements()方法的时候,就获取最新的数据并通知每个观察者。
this.temperature = temperature;
this.humidity = humidity;
this.pressure = pressure;
notifyObservers();
} }

每个布告板作为观察者,需要实现Observer接口,以“当前状态”布告板为例:

public class CurrentConditionsDisplay implements Observer{
private float temperature;
private float humidity;
CurrentConditionsDisplay(Subject weatherData) {
weatherData.registerObserver(this);
}
@Override
public void update(float temperature, float humidity, float pressure) {
this.temperature = temperature;
this.humidity = humidity;
System.out.println("update CurrentConditionDisplay,humidity:"+humidity+" temperature:"+temperature);
}
}

类似地,我们可以得到其余布告板,比如天气预报布告板:ForecastDisplay,

public class ForecastDisplay implements Observer{
private float temperature;
private float humidity;
private float pressure;
ForecastDisplay(Subject weatherData) {
weatherData.registerObserver(this);
}
@Override
public void update(float temperature, float humidity, float pressure) {
this.temperature = temperature;
this.humidity = humidity;
this.pressure = pressure;
System.out.println("update CurrentConditionDisplay,humidity:" + humidity + " temperature:" + temperature + " pressure:" + pressure);
}
}

测试代码:

public static void main(String[] args) {
WeatherData weatherData = new WeatherData();
new CurrentConditionsDisplay(weatherData);
weatherData.setMeasurements(83,3,33);
weatherData.setMeasurements(23,45,48);
weatherData.setMeasurements(4,6,8); new ForecastDisplay(weatherData);
weatherData.setMeasurements(1,2,3);
}
}

输出结果:

update CurrentConditionDisplay,humidity:3.0 temperature:83.0
update CurrentConditionDisplay,humidity:45.0 temperature:23.0
update CurrentConditionDisplay,humidity:6.0 temperature:4.0
update CurrentConditionDisplay,humidity:2.0 temperature:1.0
update CurrentConditionDisplay,humidity:2.0 temperature:1.0 pressure:3.0

JDK中内置的观察者模式

java.util.Observable;
java.util.Observer;

这两个类和我们之前讨论的SubjectObserver类似,

java.util.Observable中提供了:

setChanged(); // 表明状态已经改变
notifyObservers(); // 通知所有观察者
addObserver(Observer o); // 增加观察者

java.util.Observer中提供了:

update(); // 更新订阅信息

采用JDK内置的观察者模式修改后的WeatherData

public class WeatherData extends Observable {
private float temperature;
private float humidity;
private float pressure;
WeatherData() {
} private void measurementsChanged() {
setChanged();
notifyObservers();
}
public void setMeasurements(float temperature, float humidity, float pressure) {
this.temperature = temperature;
this.humidity = humidity;
this.pressure = pressure;
measurementsChanged();
}
float getTemperature() {
return temperature;
}
float getHumidity() {
return humidity;
}
float getPressure() {
return pressure;
} }

CurrentConditionsDisplay

public class CurrentConditionsDisplay implements Observer{
private float temperature;
private float humidity;
CurrentConditionsDisplay(Observable observable) {
observable.addObserver(this);
} @Override
public void update(Observable o, Object arg) {
if (o instanceof WeatherData) {
WeatherData weatherData = (WeatherData)o;
this.temperature = weatherData.getTemperature();
this.humidity = weatherData.getHumidity();
System.out.println("update CurrentConditionDisplay,humidity:"+humidity+" temperature:"+temperature);
}
}
}

测试代码:

public class WeatherStation {
public static void main(String[] args) {
WeatherData weatherData = new WeatherData();
new CurrentConditionsDisplay(weatherData);
weatherData.setMeasurements(83,3,33);
weatherData.setMeasurements(23,45,48);
weatherData.setMeasurements(4,6,8);
}
}

输出结果:

update CurrentConditionDisplay,humidity:3.0 temperature:83.0
update CurrentConditionDisplay,humidity:45.0 temperature:23.0
update CurrentConditionDisplay,humidity:6.0 temperature:4.0

完整代码: Observer Pattern Source

《Head First 设计模式》之观察者模式的更多相关文章

  1. java 代理模式,观察者模式

    代理模式1 import <a href="http://lib.csdn.net/base/17" class='replace_word' title="Jav ...

  2. 设计模式--观察者模式初探和java Observable模式

    初步认识观察者模式 观察者模式又称为发布/订阅(Publish/Subscribe)模式,因此我们可以用报纸期刊的订阅来形象的说明: 报社方负责出版报纸. 你订阅了该报社的报纸,那么只要报社发布了新报 ...

  3. 《JAVA与模式》之观察者模式

    转自:http://www.cnblogs.com/java-my-life/archive/2012/05/16/2502279.html 在阎宏博士的<JAVA与模式>一书中开头是这样 ...

  4. 《JAVA与模式》之观察者模式(转载)

    <JAVA与模式>之观察者模式(转载)  原文链接:http://www.cnblogs.com/java-my-life/archive/2012/05/16/2502279.html ...

  5. java设计模式7.策略模式、模板方法模式、观察者模式

    策略模式 策略模式的用意,将每一个算法封装到具有共同接口的独立的类中,从而使得它们可以相互替换.策略模式使得算法可以在不影响到客户端的情况下发生变化. 环境角色:持有一个抽象策略角色的引用. 抽象策略 ...

  6. 大型Java进阶专题(八)设计模式之适配器模式、装饰者模式和观察者模式

    前言 ​ 今天开始我们专题的第八课了.本章节将介绍:三个设计模式,适配器模式.装饰者模式和观察者模式.通过学习适配器模式,可以优雅的解决代码功能的兼容问题.另外有重构需求的人群一定需要掌握装饰者模式. ...

  7. Java设计模式之十三 ---- 观察者模式和空对象模式

    前言 在上一篇中我们学习了行为型模式的备忘录模式(Memento Pattern)和状态模式(Memento Pattern).本篇则来学习下行为型模式的最后两个模式,观察者模式(Observer P ...

  8. <代码整洁之道>、<java与模式>、<head first设计模式>读书笔记集合

    一.前言                                                                                       几个月前的看书笔记 ...

  9. Java设计模式之《观察者模式》及应用场景

    原创作品,可以转载,但是请标注出处地址:http://www.cnblogs.com/V1haoge/p/6513651.html 观察者模式,又可以称之为发布-订阅模式,观察者,顾名思义,就是一个监 ...

  10. 《java与模式》

    2012年3月 随笔档案 - java_my_life - 博客园--此网友 12年的博客都是和模式有关的,希望可以多看看.http://www.cnblogs.com/java-my-life/ar ...

随机推荐

  1. iOS 开发快速导引:TableView 和 CoreData【草】

    所有列表式的数据都是用 TableView 显示的 预览 待补充 原料 NSFetchedResultsController 用来操作 NSFetchRequst,有执行查询,监听变化,数据缓存等功能 ...

  2. android内部培训视频_第三节 常用控件(Button,TextView,EditText,AutocompleteTextView)

    第三节:常用控件 一.Button 需要掌握的属性: 1.可切换的背景 2.9.png使用 3.按钮点击事件 1)  onClick 3) 匿名类 4) 公共类 二.TextView 常用属性 1.a ...

  3. spring事务管理器设计思想(二)

    上文见<spring事务管理器设计思想(一)> 对于第二个问题,涉及到事务的传播级别,定义如下: PROPAGATION_REQUIRED-- 如果当前没有事务,就新建一个事务.这是最常见 ...

  4. [翻译] AKKA笔记- ACTORSYSTEM (配置CONFIGURATION 与调度SCHEDULING) - 4(一)

    原文在http://rerun.me/2014/10/06/akka-notes-actorsystem-in-progress/ 像我们前面看到的,我们可以用ActorSystem的actorof方 ...

  5. 【敏捷开发】Android团队开发规范

    这里说的开发规范分成目录规范,项目和包名的命名规范,类,方法,变量和常量的命名规范这几种. 目录规范 目录规范——在开发中整体文件夹组织结构. Requirement——需求文档文件夹 Design— ...

  6. PHP 基础知识测试题 答案分析

    一:选择题(单项选择,每题2分): 1. LAMP具体结构不包含下面哪种(A      ) A:Windows系统              如果是这个就是WMP B:Apache服务器 C:MySQ ...

  7. thinphp框架的项目svn重新检出后的必备配置

    刚刚试着去了解thinkphp框架,在这里做一些笔记,后续有新的总结会更新到这里,如有错误与遗漏,望大家指正. 用thinkphp框架的项目,在用svn重新检出之后,需要进行一些基本配置,方可在本地打 ...

  8. KnockoutJS 3.X API 第六章 组件(4) 自定义元素

    自定义元素提供了一种将组件注入视图的方便方法. 本节目录 介绍 例子 传递参数 父组件和子组件之间的通信 传递监控属性的表达式 将标记传递到组件中 控制自定义元素标记名称 注册自定义元素 备注1:将自 ...

  9. 服务器.htaccess 详解以及 .htaccess 参数说明(转载)

    htaccess文件(或者”分布式配置文件”)提供了针对目录改变配置的方法, 即,在一个特定的文档目录中放置一个包含一个或多个指令的文件, 以作用于此目录及其所有子目录.作为用户,所能使用的命令受到限 ...

  10. 【Win10应用开发】协议-下篇:自定义多个协议

    前面介绍了如何为应用程序自定义协议,于是有朋友会问,我希望为我的应用注册多个协议,不同的协议处理不同的事情,能吗?答案是能的. 方法主要在配置清单文件上,这里我给出一个例子,示例应用将注册两个协议,分 ...