《Head First 设计模式》之观察者模式
作者: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;
这两个类和我们之前讨论的Subject
,Observer
类似,
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 设计模式》之观察者模式的更多相关文章
- java 代理模式,观察者模式
代理模式1 import <a href="http://lib.csdn.net/base/17" class='replace_word' title="Jav ...
- 设计模式--观察者模式初探和java Observable模式
初步认识观察者模式 观察者模式又称为发布/订阅(Publish/Subscribe)模式,因此我们可以用报纸期刊的订阅来形象的说明: 报社方负责出版报纸. 你订阅了该报社的报纸,那么只要报社发布了新报 ...
- 《JAVA与模式》之观察者模式
转自:http://www.cnblogs.com/java-my-life/archive/2012/05/16/2502279.html 在阎宏博士的<JAVA与模式>一书中开头是这样 ...
- 《JAVA与模式》之观察者模式(转载)
<JAVA与模式>之观察者模式(转载) 原文链接:http://www.cnblogs.com/java-my-life/archive/2012/05/16/2502279.html ...
- java设计模式7.策略模式、模板方法模式、观察者模式
策略模式 策略模式的用意,将每一个算法封装到具有共同接口的独立的类中,从而使得它们可以相互替换.策略模式使得算法可以在不影响到客户端的情况下发生变化. 环境角色:持有一个抽象策略角色的引用. 抽象策略 ...
- 大型Java进阶专题(八)设计模式之适配器模式、装饰者模式和观察者模式
前言 今天开始我们专题的第八课了.本章节将介绍:三个设计模式,适配器模式.装饰者模式和观察者模式.通过学习适配器模式,可以优雅的解决代码功能的兼容问题.另外有重构需求的人群一定需要掌握装饰者模式. ...
- Java设计模式之十三 ---- 观察者模式和空对象模式
前言 在上一篇中我们学习了行为型模式的备忘录模式(Memento Pattern)和状态模式(Memento Pattern).本篇则来学习下行为型模式的最后两个模式,观察者模式(Observer P ...
- <代码整洁之道>、<java与模式>、<head first设计模式>读书笔记集合
一.前言 几个月前的看书笔记 ...
- Java设计模式之《观察者模式》及应用场景
原创作品,可以转载,但是请标注出处地址:http://www.cnblogs.com/V1haoge/p/6513651.html 观察者模式,又可以称之为发布-订阅模式,观察者,顾名思义,就是一个监 ...
- 《java与模式》
2012年3月 随笔档案 - java_my_life - 博客园--此网友 12年的博客都是和模式有关的,希望可以多看看.http://www.cnblogs.com/java-my-life/ar ...
随机推荐
- 浅谈Js原型的理解
一.js中的原型毫无疑问一个难点,学习如果不深入很容易就晕了! 在参考了多方面的资料后,发现解释都太过专业,对于很多还没有接触过面向对象 语言的小白来说,有理解不了里面的专有名词!如果你没 ...
- Windows Server 2012 支持的逻辑盘容量最大是多少?
这个问题似乎看起来是问系统支持最大硬盘参数?其实不然,这和文件系统有着很大关系. 磁盘在系统应用之前,要先初始化,然后创建卷,再进行格式化后完成在系统的挂载.完成这些操作之后,磁盘空间可以被系统使用. ...
- 春节前最后一篇,CRUD码农专用福利:PDF.NET之SOD Version 5.1.0 开源发布(兼更名)
废话不多说,直接入正题,明天赶着坐火车回老家过年. 从2013.10.1日起,原PDF.NET将更名为 SOD :- one SQL-MAP,ORM,Data Control framework 原P ...
- ABP理论学习之验证DTO
返回总目录 本篇目录 验证介绍 使用数据注解 自定义验证 标准化 验证介绍 首先应该验证应用的输入.用户或者其它应用都可以向该应用发送输入.在一个web应用中,验证通常要实现两次:在客户端和服务器端. ...
- 《CLR.via.C#第三版》第二部分第6,7章节读书笔记(三)
第6章讲的是类型和成员基础 重要认知:虚方法 虚方法的设计原则:设计一个类型时,应尽量减少所定义的虚方法的数量. 首先,调用虚方法的速度比调用非虚方法慢. 其次,JIT编译器不能内嵌虚方法,这进一步影 ...
- 为什么google bazel构建工具流行不起来
作者Jack47 转载请保留作者和原文出处 之前博主写了系列文章Google软件构建工具Bazel原理及使用方法介绍.最近使用了一段时间后,觉得这个东西不是一种通用的构建工具,很难对接到情况复杂的大的 ...
- maven pom中的repository节点配置没有起作用
问题描述 昨天晚上想用spring boot快速搭建一个web开发的项目,就打开spring boot的doc,按照说明开始尝试.没想到出师未捷身先死,第一步就挂了. 以下是spring boot的配 ...
- sun.misc.BASE64Encoder找不到jar包的解决方法
1.右键项目->属性->java bulid path->jre System Library->access rules->resolution选择accessible ...
- 谈谈StringBuffer和StringBuilder
(1) 速度 在执行速度方面的比较:StringBuilder > StringBuffer > String ①String 是不可变的对象(String类源码中存放字符的数组被声明为f ...
- [汇编与C语言关系]1.函数调用
对于以下程序: int bar(int c, int d) { int e = c + d; return e; } int foo(int a, int b) { return bar(a, b); ...