[head first 设计模式]第二章 观察者模式
[head first 设计模式]第二章 观察者模式
假如我们有一个开发需求——建造一个气象观测站展示系统。需求方给我们提供了一个WeatherObject对象,能够自动获得最新的测量数据。而我们要建立一个应用,有三种布告版,分别显示目前的状况,气象统计,简单预报。三种布告板能即时显示WeatherObject对象中更新的数据。
同时,我们需要这是一个可扩展的气象站,可以公布一组api,好让其他开发人员写出自己的布告板插入此应用中。
我们首先来看看我们的大致系统框架

我们的工作就算建立一个应用,利用weatherData对象取得数据,并更新布告板。
根据weatherData源文件,我们的工作是实现measurementChanged(),当测量数据备妥时,measurementChanged()方法将会被调用。

先来看一个可能的实现,

很明显,这个实现并不妥当。回想第一章的OO原则,会发现我们在针对具体实现编程,这会导致当有新需求时我们必须修改程序。同时,更新布告板的代码会经常改变,我们应该尽可能将其封装。
接下来我们将应用观察者模式来改进现有设计。
以报纸订阅为例,我们像某家报社订阅报纸,只要他们有新报纸初版,就会给派送给订户。而订户不想要了,就可以取消订阅。只要报社还在运营,就不断有人订阅或者取消订阅报纸。
出版者+订阅者=观察者模式
如果了解了报纸订阅是怎么回事,观察者模式也大体如此。出版者即为观察者模式中的主题(Subject),订阅者即为观察者模式中的观察者(Observer)。

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

观察者模式提供了一种对象设计,让主题和观察者之间松耦合。
对于观察者,主题只关心观察者实现了Observer接口,主题并不关心观察者的细节。
任何时候都可以新增观察者,因为主题唯一以来的东西是一个实现了Observer接口的对象列表,同时,也可以在任何时候删除观察者。
改变主题或观察者中的其中一方,并不会影响到另一方。
设计原则
设计应该尽可能降低交互对象之间的耦合度
依照观察者模式,得到我们的新设计

当前,我们暂时不用Java内置的观察者模式,而是自己实现这部分代码。
public interface Observer {
    public void update(float temp,float humidity,float pressure);
}
public interface Subject {
    public void notifyObserver();
    public void removeObserver(Observer observer);
    public void registerObserver(Observer observer);
}
public interface DisplayElement {
    public void display();
}
import java.util.ArrayList;
import java.util.List;
public class WeatherData implements Subject {
    private List<Observer> Observers;
    private float temperature;
    private float humidity;
    private float pressure;
    public WeatherData()
    {
        Observers = new ArrayList<Observer>();
    }
    @Override
    public void notifyObserver() {
        for (Observer o:
            Observers ) {
            o.update(temperature,humidity,pressure);
        }
    }
    @Override
    public void removeObserver(Observer observer) {
        Observers.remove(observer);
    }
    @Override
    public void registerObserver(Observer observer) {
        Observers.add(observer);
    }
    public void measurementChanged()
    {
        notifyObserver();
    }
    public void setMeasurements(float temperature,float humidity,float pressure)
    {
        this.temperature = temperature;
        this.humidity = humidity;
        this.pressure = pressure;
        measurementChanged();
    }
}
public class CurrentConditionsDisplay implements Observer,DisplayElement{
    private float temperature;
    private float humidity;
    private Subject weatherData;
    @Override
    public void display() {
        System.out.println("Current conditions: "+temperature+"F degrees and "+humidity+"% humidity");
    }
    @Override
    public void update(float temp, float humidity, float pressure) {
    this.temperature = temp;
    this.humidity = humidity;
    display();
    }
    public CurrentConditionsDisplay( Subject weatherData) {
        this.weatherData = weatherData;
        weatherData.registerObserver(this);
    }
}
public class WeatherStation {
    public static void main(String[] args) {
        WeatherData weatherData = new WeatherData();
        CurrentConditionsDisplay currentConditionsDisplay =
                new CurrentConditionsDisplay(weatherData);
        weatherData.setMeasurements(80,65,30.4f);
    }
}
使用Java内置的观察者模式
Java api有自带的观察者模式,包含Observer接口和Observable类,在使用上更加方便,很多功能已经事先准备好了。如下是我们使用Java内置观察者模式修改后的设计。

注册/删除观察者
调用Observable对象的addObserver方法和deleteObserver方法即可
被观察者送出通知
首先调用setChanged()方法,标记状态已经改变,后调用notifyObservers(),那么所有观察者都会调用自身的update方法。
import java.util.Observable;
import java.util.Observer;
public class CurrentConditionsDisplay implements Observer,DisplayElement{
    private double temperature;
    private double humidity;
    private Observable observable;
    @Override
    public void display() {
        System.out.println("Current temperature "+temperature+"F degrees and "+humidity+"%humidity");
    }
    public CurrentConditionsDisplay(Observable observable)
    {
        this.observable = observable;
        observable.addObserver(this);
    }
    @Override
    public void update(Observable o, Object arg) {
        if(o instanceof WheatherData)
        {
            temperature = ((WheatherData) o).getTemperature();
            humidity = ((WheatherData) o).getHumidity();
            display();
        }
    }
}
import java.util.ArrayList;
import java.util.List;
import java.util.Observable;
public class WheatherData extends Observable {
    private double temperature;
    private double humidity;
    private double pressure;
    public double getHumidity() {
        return humidity;
    }
    public double getPressure() {
        return pressure;
    }
    public double getTemperature()
    {
        return temperature;
    }
    public void setMeasurements(double temperature,double humidity,double pressure)
    {
        this.temperature = temperature;
        this.humidity = humidity;
        this.pressure = pressure;
        setChanged();
        notifyObservers();
    }
}
不幸的是,observable是一个类而不是接口,导致我们难以继承其他类,同时也无法拥有自己独特的实现。
在实际使用时,我们需要权衡是使用jdk自带的观察者模式亦或是由自己实现。
[head first 设计模式]第二章 观察者模式的更多相关文章
- 设计模式之第18章-观察者模式(Java实现)
		设计模式之第18章-观察者模式(Java实现) 话说曾小贤,也就是陈赫这些天有些火,那么这些明星最怕的,同样最喜欢的是什么呢?没错,就是狗仔队.英文的名字比较有意思,是paparazzo,这一说法据说 ... 
- Head First 设计模式 第2章 观察者模式
		第2章.观察者模式 1.定义: 在对象之间定义一对多关系,当一个对象改变状态时,该对象的依赖会收到通知,并自动更新. 2.介绍 在介绍观察者模式之前,先来说一个日常生活中经常碰到的事(可能现在的人碰到 ... 
- 设计模式学习之“观察者模式” [C#]
		<深入浅出设计模式>学习笔记第二章 需求: 开发一套气象监测应用,如图: 气象站,目前有三种装置,温度.湿度和气压感应装置. WeatherData对象追踪气象站的数据,并更新到布告板,布 ... 
- 第二章 OO大原则
		昨天忙了一天,晚上加班到了12点,虽然工作有时候比较累,但是整体来讲还是比较轻松的,国企加上我是今年才毕业的应届生,导致了现在这种情况.工资也真的不算高...但我觉得最开始还是要踏踏实实一点比较好.学 ... 
- (转)iOS Wow体验 - 第二章 - iOS用户体验解析(2)
		本文是<iOS Wow Factor:Apps and UX Design Techniques for iPhone and iPad>第二章译文精选的第二部分,其余章节将陆续放出.上一 ... 
- (转)iOS Wow体验 - 第二章 - iOS用户体验解析(1)
		本文是<iOS Wow Factor:Apps and UX Design Techniques for iPhone and iPad>第二章译文精选的第一部分,其余章节将陆续放出.上一 ... 
- [HeadFirst-JSPServlet学习笔记][第二章:高层概述]
		第二章:高层体系结构 容器 1 什么是容器? servelet没有main()方法.它们受控于另一个Java应用,这个Java应用称为容器(Container) Tomcat就是这样一个容器.Web服 ... 
- Knockout应用开发指南 第二章:监控属性(Observables)
		原文:Knockout应用开发指南 第二章:监控属性(Observables) 关于Knockout的3个重要概念(Observables,DependentObservables,Observabl ... 
- 第16章 观察者模式(Oberver Pattern)
		原文 第16章 观察者模式(Oberver Pattern) 观察者模式 概述: 在软件构建过程中,我们需要为某些对象建立一种“通知依赖关系” ——一个对象(目标对象)的状态发生改变,所有的依 ... 
随机推荐
- jinjia2语言
			金家兔 网站: https://jinja.palletsprojects.com/en/2.11.x/ #Jinja is Beautiful {% extends "layout.htm ... 
- Html+Ajax+Webservice  实现文件跨域上传
			1. 界面HTML <p >上传文件: <input id="zfiles" type="file" name="file" ... 
- 一篇文章 图解Python 玩转Python
			0 Python 解释器:1.Python数据结构:2.变量与运算符3 Python 流程控制 4 Python 文件处理5 python 输入输出6 Python 异常7 Python 函数和模块8 ... 
- 虚拟机之kali2.0
			kali2.0下载地址: 链接: https://pan.baidu.com/s/1CiQJNfvUPFw3aJR103XSbg 提取码: 57wp 
- 在Vue中使用Echart图表库。【全网最简单】
			使用npm安装echart npm install echarts --save 然后在使用的页面上直接import import echarts from "echarts"; ... 
- (python)getattr等用法
			getattr() 函数用于返回一个对象属性值; 语法 getattr(object, name[, default]) 参数 object -- 对象. name -- 字符串,对象属性. defa ... 
- java处理大数据量任务时的可用思路--未验证版,具体实现方法有待实践
			1.Bloom filter适用范围:可以用来实现数据字典,进行数据的判重,或者集合求交集基本原理及要点:对于原理来说很简单,位数组+k个独立hash函数.将hash函数对应的值的位数组置1,查找时如 ... 
- 定位流之z-index属性
			1.固定定位是脱离标准流的,不会占用标准流的空间 2.和绝对定位有点像,也不区分行内块级元素 3.类似于前面学的背景关联方式(让某个背景图片不随滚动而滚动)让某个元素不随着滚动条的滚动而滚动 ie6不 ... 
- Windows Server 2019 在桌面图标
			直接按Win(键盘上的微软徽标键)+R,输入: rundll32.exe shell32.dll,Control_RunDLL desk.cpl,,0 回车 rundll32.exe shell32. ... 
- 关于LoRa安全联盟的六大常见问题
			LoRaWAN的安全机制在哪里指定? 所有安全机制都在LULA联盟规范中指定,可以由公众下载. LoRa联盟规范如何保证LoRaWAN网络的安全操作? LoRaWAN支持来源认证.完整的媒体访问控制( ... 
