1. 程式人生 > >java相關技術(partner4java專欄)希望對您的學習有所幫助

java相關技術(partner4java專欄)希望對您的學習有所幫助

觀察者模式:定義了物件之間的一對多的依賴,這樣一來,當一個物件改變狀態時,他的所有者就會立刻接到通知並自動更新。
觀察者模式定義了一系列物件之間的一對多關係。
當一個物件改變狀態,當其他依賴者都會收到通知。

實現觀察者模式的方法不止一種,但是以包含Subject與Observer介面的類的設計最為常見。

這和一對多的關係有何關聯?
利用觀察者模式,主題是具有狀態的物件,並且可以控制這些狀態。也就是說,有“一個”具有狀態的主題。
另一方面,觀察者使用這些狀態,雖然這些狀態並不屬於他們。有許多的觀察者,依賴主題來告訴他們狀態
何時改變了。這就產生了一個關係:“一個”主題對“多個”觀察者的關係。

期間的依賴是如何產生的?
因為主題是真正擁有資料的人,觀察者是主題的依賴者,在資料變化更新,這樣比起讓許多物件控制一份資料來,可以得到更乾淨OO設計。

設計原則:為了互動物件之間的鬆耦合設計而努力

Demo:

業務場景:

建立一個應用,有三種佈告板,分別顯示目前的狀況、氣象統計及簡單的預報。
當WeatherObject物件獲得最新的測量資料時,三種佈告板必須實時更新。

這是一個可以擴充套件的氣象站,其他開發人員可以寫出自己的氣象佈告板,並插入到應用中。

package cn.partner4java.weather;


/**
 * 主業務類(管理觀察員、並負責呼叫觀察員)
 * @author partner4java
 *
 */
public interface Subject {
	
	/**
	 * 註冊觀察員
	 * @param observer 觀察員
	 */
	public void registerObserver(Observer observer);
	
	/**
	 * 刪除觀察員
	 * @param observer 觀察員
	 */
	public void removeObserver(Observer observer);
	
	/**
	 * 通知所有的觀察者
	 */
	public void notifyObserver();
}

package cn.partner4java.weather;


/**
 * 佈告板
 * (如:目前狀況佈告板、統計佈告板、預測佈告板)
 * @author partner4java
 *
 */
public interface DisplayElement {
	
	/**
	 * 佈告呼叫方法
	 */
	public void display();

}

package cn.partner4java.weather;


/**
 * 觀察員(氣象發生改變時,被呼叫的物件)
 * @author partner4java
 *
 */
public interface Observer {
	/**
	 * 所有的觀察者都必須實現這個方法,以實現觀察者介面
	 * @param temperature 溫度
	 * @param humidity 溼度
	 * @param pressure 氣壓
	 */
	public void update(float temperature,float humidity,float pressure);
}

package cn.partner4java.weather.impl;

import java.util.ArrayList;
import java.util.List;

import cn.partner4java.weather.Observer;
import cn.partner4java.weather.Subject;


/**
 * 氣象資料獲取類
 * 主業務類(管理觀察員、並負責呼叫觀察員)
 * 實現主體介面
 * @author partner4java
 *
 */
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(int i=0;i<observers.size();i++){
			Observer observer = observers.get(i);
			observer.update(temperature, humidity, pressure);
		}
	}

	@Override
	public void registerObserver(Observer observer) {
		int i = observers.indexOf(observer);
		if(i == -1){
			observers.add(observer);
		}
	}

	@Override
	public void removeObserver(Observer observer) {
		int i = observers.indexOf(observer);
		if(i >= 0){
			observers.remove(i);
		}
	}
	
	
	/**
	 * 當從氣象站得到更新觀測值時,我們通知觀察者
	 */
	public void measurementsChanged(){
		notifyObserver();
	}

	
	/**
	 * 設定氣象改變資料
	 * @param temperature 溫度
	 * @param humidity 溼度
	 * @param pressure 氣壓
	 */
	public void setMeasurements(float temperature,float humidity,float pressure){
		this.temperature = temperature;
		this.humidity = humidity;
		this.pressure = pressure;
		measurementsChanged();
	
	}
	
	
	public List<Observer> getObservers() {
		return observers;
	}

	public void setObservers(List<Observer> observers) {
		this.observers = observers;
	}

	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;
	}
	
	

}

package cn.partner4java.weather.impl;

import cn.partner4java.weather.DisplayElement;
import cn.partner4java.weather.Observer;
import cn.partner4java.weather.Subject;


/**
 * 目前狀況佈告板
 * @author partner4java
 *
 */
public class CurrentConditionsDisplay implements Observer, DisplayElement {
	private float temperature;
	private float humidity;
	private Subject weatherData;
	
	public CurrentConditionsDisplay(Subject weatherData){
		this.weatherData = weatherData;
		this.weatherData.registerObserver(this);
	}
	
	@Override
	public void update(float temperature, float humidity, float pressure) {
		this.temperature = temperature;
		this.humidity = humidity;
		display();
	}

	@Override
	public void display() {
		System.out.println("CurrentConditionsDisplay: temperature-" + temperature +  
				" humidity-" + humidity);
	}

}

package cn.partner4java.weather.impl;

import cn.partner4java.weather.DisplayElement;
import cn.partner4java.weather.Observer;


/**
 * 未來天氣預告版
 * @author partner4java
 *
 */
public class ForecastDisplay implements DisplayElement, Observer {
	/** 當前氣壓 */
	private float currentPressure = 29.92f;  
	/** 最後一次氣壓 */
	private float lastPressure;
	private WeatherData weatherData;
	
	
	public ForecastDisplay(WeatherData weatherData) {
		this.weatherData = weatherData;
		weatherData.registerObserver(this);
	}
	
	@Override
	public void display() {
		System.out.print("Forecast: ");
		if (currentPressure > lastPressure) {
			System.out.println("Improving weather on the way!");
		} else if (currentPressure == lastPressure) {
			System.out.println("More of the same");
		} else if (currentPressure < lastPressure) {
			System.out.println("Watch out for cooler, rainy weather");
		}
	
	}

	@Override
	public void update(float temperature, float humidity, float pressure) {
		lastPressure = currentPressure;
		currentPressure = pressure;
		display();
	}

}
package cn.partner4java.weather.impl;

import cn.partner4java.weather.DisplayElement;
import cn.partner4java.weather.Observer;


/**
 * 統計狀態佈告
 * @author partner4java
 *
 */
public class StatisticsDisplay implements DisplayElement, Observer {
	/** 最高溫度 */
	private float maxTemp = 0.0f;
	/** 最低溫度 */
	private float minTemp = 200;
	/** 記錄總溫度 */
	private float tempSum = 0.0f;
	/** 溫度讀取次數 */
	private int countReadings;
	private WeatherData weatherData;
	
	public StatisticsDisplay(WeatherData weatherData) {
		this.weatherData = weatherData;
		weatherData.registerObserver(this);
	}
	
	@Override
	public void display() {
		System.out.println("StatisticsDisplay: maxTemp-" + 
				maxTemp + " minTemp-" + minTemp + " averageTemp-" + 
				tempSum/countReadings);
		
	}

	@Override
	public void update(float temperature, float humidity, float pressure) {
		tempSum += temperature;
		countReadings++;
		if(temperature < minTemp){
			minTemp = temperature;
		}else if(temperature > maxTemp){
			maxTemp = temperature;
		}
		display();
	}

}


package cn.partner4java.weather.test;

import cn.partner4java.weather.impl.CurrentConditionsDisplay;
import cn.partner4java.weather.impl.ForecastDisplay;
import cn.partner4java.weather.impl.StatisticsDisplay;
import cn.partner4java.weather.impl.WeatherData;


/**
 * 氣象站測試(啟動氣象站)
 * @author partner4java
 *
 */
public class WeatherStation {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		WeatherData weatherData = new WeatherData();
		CurrentConditionsDisplay currentConditionsDisplay = new CurrentConditionsDisplay(weatherData);
		StatisticsDisplay statisticsDisplay = new StatisticsDisplay(weatherData);
		ForecastDisplay forecastDisplay = new ForecastDisplay(weatherData);
		
		weatherData.setMeasurements(80, 234, 20.4f);
		weatherData.setMeasurements(56, 232, 20.4f);
		weatherData.setMeasurements(34, 123, 20.4f);
		
	}

}