設計模式二:觀察者模式(java內置)

把對象變成觀察者:實現觀察者接口(java.util.Observer),而後調用Observable對象的addObserver()方法或deleteObserver()java

可觀察者送出通知:ide

一、擴展java.util.Observable類產生"可觀察者"類測試

2 、1)先調用Observable的setChanged()方法,標記主題的狀態已經改變,讓notifyObservers()知道當它被調用時應該更新觀察者,若是調用notifyObservers()以前沒有調用setChanged(),觀察者就不會被通知更新。this

Observable的setChanged()方法(修飾符是protected,不能建立Observable實例並組合到本身的對象中由於不能使用setChanged()方法,除非繼承Observable類):code

protected synchronized void setChanged() {
        changed = true;
    }

      2)調用兩種notifyobservers()方法中的一個:server

notifyobservers()或notifyobservers(Object arg)對象

java.util.Observable的notifyobservers(Object arg)的方法:繼承

Object arg:當通知時,能夠把arg(數據對象data object)經過update方法傳送給每個觀察者接口

public void notifyObservers(Object arg) {
        Object[] arrLocal;
        synchronized (this) {
            if (!changed)
                return;
            arrLocal = obs.toArray();
            clearChanged();
        }

        for (int i = arrLocal.length-1; i>=0; i--)
            ((Observer)arrLocal[i]).update(this, arg);
    }

java.util.Observable的notifyobservers()方法:rem

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

觀察者如何接收通知:

觀察者實現了跟新的方法:

update(Observable o,Object arg)

Observable o:主題自己看成第一個變量,好讓觀察者知道是哪一個主題通知它的

Object arg:是傳入notifyobservers()的數據對象,若是沒有則說明爲空。

若是想"推"(push)數據給觀察者,能夠把數據看成數據對象傳送給notifyobservers()方法。不然,觀察者必須從可觀察者對象中"拉"(pull)數據。

下面經過觀察者從可觀察者處拉數據的演示:

一、把WeatherData改爲使用java.util.Observable

package com.ya;

import java.util.ArrayList;
import java.util.Observable;

public class WeatherData extends Observable{
    private float temperature;
    private float humidity;
    private float pressure;
    
    public WeatherData(){    }
    
    public void measurementsChanged(){
        //調用notifyObservers()方法以前先調用setChanged()
    	setChanged();
        //若是該方法的參數沒有Object數據對象,這表示採用的是觀察者主動向可觀察者"拉"的方式
    	notifyObservers();
    }
    public void setMeasurements(float temperature,float humidity,float pressure){
    	this.temperature = temperature;
    	this.humidity = humidity;
    	this.pressure = pressure;
    	measurementsChanged();
    }
  //下面三個方法,由於咱們要使用"拉"的作法,觀察者會利用這些方法得到WeatherData對象的狀態
    public float getTemperature(){
    	return temperature;
    }
    
    public float getHumidity(){
    	return humidity;
    }
    
    public float getPressure(){
    	return pressure;
    }
    
}

CurrentConditionsDisplay佈告板:

package com.ya;

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

public class CurrentConditionsDisplay implements Observer,DisplayElement{
	Observable observable;
	private float temperature;
	private float humidity;
	private float pressure;
	public CurrentConditionsDisplay(Observable observable) {
		this.observable = observable;
		observable.addObserver(this);
	}
	
	@Override
	public void update(Observable obs, Object obj) {
		if(obs instanceof WeatherData){
			WeatherData weatherData = (WeatherData)obs;
			this.temperature = weatherData.getTemperature();
			this.humidity = weatherData.getHumidity();
			display();
		}
		display();
	}
	
	public void display(){
		System.out.println("Current conditions:" + temperature + "F degrees and"+ humidity +" %humidity");
	}

}

測試代碼類WeatherStation:

package com.ya;

public class WeatherStation {
    public static void main(String[] args) {
        WeatherData weatherData = new WeatherData();
        CurrentConditionsDisplay currentDisplay = new CurrentConditionsDisplay(weatherData);
        weatherData.setMeasurements(80, 65, 30.4f);
        weatherData.setMeasurements(82, 70, 29.2f);
    }
}

有多個公佈板時(觀察者),測試結果每次輸出的次序不同,而自定義觀察者的模式輸出次序每次輸出都同樣。

這是由於java.util.Observable實現了notifyObservers()方法,調用觀察者的update的次序與自定義的觀察者模式不同。

//java內置的可觀察者調用觀察者的update的次序是後加入的先調用
for (int i = arrLocal.length-1; i>=0; i--)
            ((Observer)arrLocal[i]).update(this, arg);
//自定義的觀察者模式調用觀察者的update的次序是先加入的先調用
for(int i=0;i<observers.size();i++){
  Observer observer = (Observer)observers.get(i);
  observer.update(temperature,humidity,pressure);
}

在JDK中,不是隻有java.util中才能找到觀察者模式,在JavaBeans和Swing中,也都實現了觀察者模式。

相關文章
相關標籤/搜索