天天看點

java設計模式——觀察者模式認識觀察者模式使用JDK内置的觀察者模式的一個例子Java内置的觀察者模式如何運作使用内置觀察者模式的弊端

認識觀察者模式

我們看看報紙和雜志的訂閱是怎麼回事:

       1.報社的業務就是出版報紙。

       2.向某家報社訂閱報紙,隻要他們有新報紙出版,就會給你送

       來。隻要你是他們的訂戶,你就會一直收到新報紙。

       3.當你不想再看報紙的時候,取消訂閱,他們就不會再送新報

       紙來。

       4.隻要報社還在營運,就會一直有人(或機關)向他們訂閱報

       紙或取消訂閱報紙。

使用JDK内置的觀察者模式的一個例子

可觀察者

import java.util.Observable;    //類
import java.util.Observer;      //接口
	
public class WeatherData extends Observable {
	private float temperature;
	private float humidity;
	private float pressure;
	
	public WeatherData() { }
	
	public void measurementsChanged() {
		setChanged();
		notifyObservers();
	}
	
	public void setMeasurements(float temperature, float humidity, float pressure) {
		this.temperature = temperature;
		this.humidity = humidity;
		this.pressure = pressure;
		measurementsChanged();
	}
	
	public float getTemperature() {
		return temperature;
	}
	
	public float getHumidity() {
		return humidity;
	}
	
	public float getPressure() {
		return pressure;
	}
}
           

可觀察者(釋出消息給觀察者可以是可觀察者者固定推送,或者是觀察者根據需要适時拉取)

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

接口DisplayElement

public interface DisplayElement {
	public void display();
}
           

Java内置的觀察者模式如何運作

如何把對象變成觀察者……

  如同以前一樣,實作觀察者接口(java.uitl.Observer),然後調用任何Observable對

  象的addObserver()方法。不想再當觀察者時,調用deleteObserver()方法就可以了。

可觀察者要如何送出通知 ……

  首先,你需要利用擴充java.util.Observable接口産生“可觀察者”類,然後,需要兩

  個步驟:

    1.先調用setChanged()方法,标記狀态已經改變的事實。(該方法根據需要調用,但是未調用該方法就調用notifyObervers(),觀察者不會“被通知”)

    2.然後調用兩種notifyObservers()方法中的一個:

         notifyObservers() 或 notifyObservers(Object arg)

觀察者如何接收通知 ……

    update(Observable o, Object arg)

   主題本身當作第一個變量,好讓觀察者知道是哪個主題通知它的,而第二個參數正是傳入notifyObservers()的資料對象。如果沒有說明    則為空。如果想要“推”資料給觀察者,可以把資料當做資料對象傳送給notifyObvers(args)方法,否則,觀察者就必須從可觀察者對象中“拉”對象。

使用内置觀察者模式的弊端

Observable是一個類

你已經從我們的原則中得知這不是一件好事,但是,這到底會造成什麼問題呢?

首先,因為Observable是一個“類”,你必須設計一個類繼承它。如果某類想同時

具有Observable類和另一個超類的行為,就會陷入兩難,畢竟Java不支援多重繼承。

這限制了Observable的複用潛力(而增加複用潛力不正是我們使用模式最原始的動

機嗎?)。

再者,因為沒有Observable接口,是以你無法建立自己的實作,和Java内置的

Observer API搭配使用,也無法将java.util的實作換成另一套做法的實作(比方說,

Observable将關鍵的方法保護起來

如果你能夠擴充java.util.Observable,那麼Observable“可能”可以符合你的需求。

否則,你可能需要像本章開頭的做法那樣自己實作這一整套觀察者模式。不管用

哪一種方法,反正你都已經熟悉觀察者模式了,應該都能善用它們。

如果你看看Observable API,你會發現setChanged()方法被保護起來了(被定義成

protected)。那又怎麼樣呢?這意味着:除非你繼承自Observable,否則你無法

建立Observable執行個體并組合到你自己的對象中來。這個設計違反了第二個設計原

則:“多用組合,少用繼承”。

繼續閱讀