設計模式系列—觀察者(Observer)模式

HeadFirst設計模式讀書筆記

觀察者模式

一线椰,簡介

  1. 什么是觀察者模式胞谈?
    定義:觀察者模式定義了對象之間的一對多依賴,這樣一來憨愉,當一個對象改變狀態(tài)時烦绳,他的所有依賴者都會收到通知并自動更新。
    理解:類似于報紙訂閱配紫,向某家報社(被觀察者)訂閱報紙径密,只要有新報紙出版,他就會把新報紙送到訂閱者(觀察者)手中躺孝。同時訂閱者可以取消訂閱這份報紙享扔。
  2. 現(xiàn)在還是書中的例子:被觀察者是氣象數(shù)據WeatherData,觀察者是氣象顯示板CurrentConditionDisplay括细,類圖如下:


    observer

二伪很,自定義觀察者模式代碼實現(xiàn)

1,三個接口如下:

package interfaces;
public interface Subject {
    public void registerObserver(Observer o);
}

public interface Observer {
    public void update(float temp,float humidity,float pressure);
}

public interface DisplayElement {
    public void display();
}

2奋单,WeatherData的實現(xiàn)

package implementObjObserver;

import java.util.ArrayList;

import interfaces.Observer;
import interfaces.Subject;

public class WeatherData implements Subject{
private ArrayList observers;
private float temperature;
private float humidity;
private float pressure;

public WeatherData(){
    observers = new ArrayList();
}

public void removeObserver(Observer o){
    int i = observers.indexOf(o);
    if(i>=0){
        observers.remove(i);
    }
}

public void notifyObservers(){
    for(int i = 0; i < observers.size(); i++){
        Observer observer =(Observer)observers.get(i);
        observer.update(temperature, humidity, pressure);
    }
}
@Override
public void registerObserver(Observer o) {
    // TODO Auto-generated method stub
    observers.add(o);
}

public void setMeasurements(float temperature,float humidity,float pressure){
    this.temperature = temperature;
    this.humidity = humidity;
    this.pressure = pressure;
    measurementsChanged();
}

public void measurementsChanged(){
    notifyObservers();
}
}

3锉试,CurrentConditionDisplay代碼如下

package implementObjObserver;

import interfaces.DisplayElement;
import interfaces.Observer;
import interfaces.Subject;

public class CurrentConditionsDisplay implements Observer,DisplayElement {
private float temperature;
private float humidity;
private Subject weatherData;

public CurrentConditionsDisplay(Subject weatherData) {
    // TODO Auto-generated constructor stub
    this.weatherData = weatherData;
    weatherData.registerObserver(this);
}

@Override
public void update(float temp, float humidity, float pressure) {
    // TODO Auto-generated method stub
    this.temperature = temp;
    this.humidity = humidity;
    display();
}

@Override
public void display() {
    // TODO Auto-generated method stub
    System.out.println("Current conditions: " + temperature + "F degrees and "
    + humidity + "%humidity");
}

}

4,測試代碼

package implementObjObserver;

public class WeatherStation {
public static void main(String[] args) {
    WeatherData weatherData = new WeatherData();
    CurrentConditionsDisplay currentDisplay = new CurrentConditionsDisplay(weatherData);
    weatherData.setMeasurements(80, 12, 20.4f);
}
}

三览濒,JDK中的觀察者模式

1呆盖,簡介

jdk中內置了觀察者模式,但是Observable是一個類不是一個接口贷笛,那么久降低了其擴展性应又,因為一個類只能繼承一個類。

2乏苦,需要注意的部分

  • 增加了一個setChanged方法株扛。
  • 兩種通知觀察者的方式:
  1. notifyObservers();采用這種方式尤筐,觀察者需要用拉的方式獲取更新(在下面的代碼中可以看到)
  2. notifyObservers(Object obj);這是一種推數(shù)據的方式,直接將一個object對象通知給每一個觀察者洞就。

四盆繁,使用JDK封裝的觀察者模式實現(xiàn)代碼

1,不需要提供observer和observable接口旬蟋,只需要提供一個每個顯示板都需要實現(xiàn)display方法的接口

public interface DisplayElement {
public void display();
}

2油昂,WeatherData需要繼承jdk提供的Observable類,其中注冊observer的list以及notifyObserver()具體的實現(xiàn)都已經被jdk內部實現(xiàn)好了倾贰。

package com.liu;

import java.util.Observable;

public class WeatherData extends Observable {
private float temperature;
private float humidity;
private float pressure;

public void messureChanged(){
    setChanged();
    notifyObservers();
}

public void setMessurements(float tem, float humi,float pre){
    this.temperature = tem;
    this.humidity = humi;
    this.pressure = pre;
    messureChanged();
}
//因為采用的是notifyObservers()方法冕碟,所以采用的是拉的方式更新數(shù)據,所以需要提供get方法匆浙。
public float getTemperature(){
    return temperature;
}

public float getHumidity(){
    return humidity;
}

public float getPressure(){
    return pressure;
}
}

3安寺,觀察者實現(xiàn)jdk提供的Observer接口,那么會使用內部封裝好的update()方法吞彤,所以需要注意類型強轉我衬。

package com.liu;

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

public class CurrentConditionsDisplay implements Observer, DisplayElement {
private Observable observable;
private float temperature;
private float humidity;

public CurrentConditionsDisplay(Observable observable) {
    // TODO Auto-generated constructor stub
    this.observable = observable;
    observable.addObserver(this);
}

@Override
public void display() {
    // TODO Auto-generated method stub
    System.out.println("Current conditions: " + temperature + "F degrees and "
    + humidity + "%humidity");
}

@Override
public void update(Observable o, Object arg) {
    // TODO Auto-generated method stub
    if(o instanceof WeatherData){
        WeatherData weatherData = (WeatherData)o;
        this.temperature = weatherData.getTemperature();
        this.humidity = weatherData.getHumidity();
        display();
    }
}

}

4,代碼結果測試

public class WeatherStation {
public static void main(String[] args) {
    WeatherData weatherData = new WeatherData();
    CurrentConditionsDisplay currentDisplay = new CurrentConditionsDisplay(weatherData);
    weatherData.setMessurements(12, 12, 12);
}
}

五饰恕,JDK中提到的還有一個notifyObserver(Object obj)的方法可以通知觀察者

1,創(chuàng)建一個Datas類

package com.liu;

public class Datas {
private float temperature;
private float humidity;
private float pressure;

public Datas() {
    // TODO Auto-generated constructor stub
}
public float getTemperature() {
    return temperature;
}
public void setTemperature(float temperature) {
    this.temperature = temperature;
}
public float getHumidity() {
    return humidity;
}
public void setHumidity(float humidity) {
    this.humidity = humidity;
}
public float getPressure() {
    return pressure;
}
public void setPressure(float pressure) {
    this.pressure = pressure;
}   
}

2井仰,被觀察者需要改為:

import java.util.Observable;

public class WeatherData extends Observable {
private float temperature;
private float humidity;
private float pressure;

private Datas data = new Datas();

public void messureChanged(){
    setChanged();
    notifyObservers(data);
}

public void setMessurements(float tem, float humi,float pre){
    data.setTemperature(tem);
    data.setHumidity(humi);
    data.setPressure(pre);
    messureChanged();
}
}

3埋嵌,觀察者:

package com.liu;

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

public class CurrentConditionsDisplay implements Observer, DisplayElement {
private Observable observable;
private float temperature;
private float humidity;

public CurrentConditionsDisplay(Observable observable) {
    // TODO Auto-generated constructor stub
    this.observable = observable;
    observable.addObserver(this);
}

@Override
public void display() {
    // TODO Auto-generated method stub
    System.out.println("Current conditions: " + temperature + "F degrees and "
    + humidity + "%humidity");
}

@Override
public void update(Observable o, Object obj) {
    // TODO Auto-generated method stub
    if(o instanceof WeatherData){
        WeatherData weatherData = (WeatherData)o;
        Datas data = (Datas)obj;
        this.temperature = data.getTemperature();
        this.humidity = data.getHumidity();
        display();
    }
}

}

4,測試代碼不變

public class WeatherStation {
public static void main(String[] args) {
    WeatherData weatherData = new WeatherData();
    CurrentConditionsDisplay currentDisplay = new CurrentConditionsDisplay(weatherData);
    weatherData.setMessurements(14, 12, 12);
}
}
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末俱恶,一起剝皮案震驚了整個濱河市雹嗦,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌合是,老刑警劉巖了罪,帶你破解...
    沈念sama閱讀 218,941評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異聪全,居然都是意外死亡泊藕,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評論 3 395
  • 文/潘曉璐 我一進店門难礼,熙熙樓的掌柜王于貴愁眉苦臉地迎上來娃圆,“玉大人,你說我怎么就攤上這事蛾茉∷夏兀” “怎么了?”我有些...
    開封第一講書人閱讀 165,345評論 0 356
  • 文/不壞的土叔 我叫張陵谦炬,是天一觀的道長悦屏。 經常有香客問我,道長,這世上最難降的妖魔是什么础爬? 我笑而不...
    開封第一講書人閱讀 58,851評論 1 295
  • 正文 為了忘掉前任甫贯,我火速辦了婚禮,結果婚禮上幕帆,老公的妹妹穿的比我還像新娘获搏。我一直安慰自己,他們只是感情好失乾,可當我...
    茶點故事閱讀 67,868評論 6 392
  • 文/花漫 我一把揭開白布常熙。 她就那樣靜靜地躺著,像睡著了一般碱茁。 火紅的嫁衣襯著肌膚如雪裸卫。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,688評論 1 305
  • 那天纽竣,我揣著相機與錄音墓贿,去河邊找鬼。 笑死蜓氨,一個胖子當著我的面吹牛聋袋,可吹牛的內容都是我干的。 我是一名探鬼主播穴吹,決...
    沈念sama閱讀 40,414評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼幽勒,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了港令?” 一聲冷哼從身側響起啥容,我...
    開封第一講書人閱讀 39,319評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎顷霹,沒想到半個月后咪惠,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經...
    沈念sama閱讀 45,775評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡淋淀,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年遥昧,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片绅喉。...
    茶點故事閱讀 40,096評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡渠鸽,死狀恐怖,靈堂內的尸體忽然破棺而出柴罐,到底是詐尸還是另有隱情徽缚,我是刑警寧澤,帶...
    沈念sama閱讀 35,789評論 5 346
  • 正文 年R本政府宣布革屠,位于F島的核電站凿试,受9級特大地震影響排宰,放射性物質發(fā)生泄漏。R本人自食惡果不足惜那婉,卻給世界環(huán)境...
    茶點故事閱讀 41,437評論 3 331
  • 文/蒙蒙 一板甘、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧详炬,春花似錦盐类、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,993評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至隐岛,卻和暖如春猫妙,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背聚凹。 一陣腳步聲響...
    開封第一講書人閱讀 33,107評論 1 271
  • 我被黑心中介騙來泰國打工割坠, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人妒牙。 一個月前我還...
    沈念sama閱讀 48,308評論 3 372
  • 正文 我出身青樓彼哼,卻偏偏與公主長得像,于是被迫代替她去往敵國和親湘今。 傳聞我的和親對象是個殘疾皇子沪羔,可洞房花燭夜當晚...
    茶點故事閱讀 45,037評論 2 355

推薦閱讀更多精彩內容

  • 1 場景問題# 1.1 訂閱報紙的過程## 來考慮實際生活中訂閱報紙的過程,這里簡單總結了一下象浑,訂閱報紙的基本流程...
    七寸知架構閱讀 4,622評論 5 57
  • 前言我從去年開始使用 RxJava ,到現(xiàn)在一年多了琅豆。今年加入了 Flipboard 后愉豺,看到 Flipboard...
    占導zqq閱讀 9,164評論 6 151
  • 觀察者(Observer)模式 走進觀察者模式 首先,先思考訂閱報紙是怎么回事報社的業(yè)務就是出版報紙茫因,并把報紙送給...
    廖少少閱讀 409評論 3 0
  • 我從去年開始使用 RxJava 蚪拦,到現(xiàn)在一年多了。今年加入了 Flipboard 后冻押,看到 Flipboard 的...
    Jason_andy閱讀 5,473評論 7 62
  • 東月山下有東湖驰贷,東湖連海共潮升。 我叫姜楓洛巢,四歲括袒,那一天是古歷四月二十八,是不是吉日不知道稿茉,反正老爹不在山上锹锰,我便...
    何季風停閱讀 1,075評論 0 0