設計模式入門-觀察者模式

      現在是大三寒假,在大二暑假時進入國內某互聯網上市公司做Android開發,半年多的學習和工作積累了很多,剛好現在下班後不用急的趕回去上課,就留在公司寫博客總結一下。《設計模式》這本經典的書是之前在公交車上讀的,現在計劃每隔一段時間總結一個專題,回顧一下。今天回顧一下第一個模式:觀察者模式。由於本人能力有限,這也是本人寫的第一篇博客,有錯誤的地方希望各位大神指點。

認識觀察者模式

舉一個生活中的例子,報社的業務是出版報紙,如果你向報社訂閱了報紙,那麼他們只要有新報紙出版,就會給你送來,如果你不想看了,可以取消訂閱,那麼他們就不會把報紙送來了。他們可以有很多個訂閱者,只要報社在運營,就會一直有人想他們訂閱或取消訂閱報紙。

出版者+訂閱者=觀察者模式

     如果你瞭解了的訂閱是怎麼回事,那麼你就明白了觀察者模式是怎麼回事,在這裏“出版者”被稱爲“主題”(Subject),“訂閱者”被稱爲“觀察者”(Observer)。

                 

觀察者模式

        定義了對象之間的一對多依賴,當一個對象發生改變時,它所有的依賴者就會搜到通知,並自動更新。

式中的角色

    1.抽象主題角色(Subject):目標角色知道它的觀察者,可以有任意多個觀察者觀察同一個目標。並且提供註冊和刪除觀察者對象的接口。目標角色往往由抽象類或者接口來實現。

    2. 抽象觀察者角色(Observer):爲那些在目標發生改變時需要獲得通知的對象定義一個更新接口。抽象觀察者角色主要由抽象類或者接口來實現。

    3.具體主題角色(Concrete Subject):將有關狀態存入各個Concrete Observer對象。當它的狀態發生改變時, 向它的各個觀察者發出通知。

    4.具體觀察者角色(Concrete Observer):存儲有關狀態,這些狀態應與目標的狀態保持一致。實現Observer的更新接口以使自身狀態與目標的狀態保持一致。在本角色內也可以維護一個指向Concrete Subject對象的引用。

 實際工程項目中的應用

     下面來結合一個實際工程項目:氣象監測站會將傳感器收集到的數據(溫度Temperature,溼度Humidity,氣壓Pressure)傳給WeatherData對象,利用該對象來實時更新顯示三個佈告板:目前天氣狀況(CurrentConditions),氣象統計(Statistics)和天氣預報(Forecast)。

     觀察者模式定義了一對多的依賴關係,這樣一來,當一個對象改變狀態時,它的所有依賴者都會收到通知並更新。那麼WeatherData類就是“一”,“多”就是使用天氣觀測的各種佈告板。我們把WeatherData對象當做“主題(Subject)",把佈告板當做觀察者,佈告板爲了取得信息,向WeatherData對象註冊。一旦WeatherData對象知道某個佈告板的存在,就會調用update方法,來對佈告板進行更新。update是在觀察者Observer接口中定義的。

類圖



實現代碼

主題Subject接口:利用該接口中的函數可以註冊,移除和通知觀察者

public interface Subject {
    
    public void registerObserver(Observer o);
    public void removeObserver(Observer o);
    public void notifyObservers();

}

觀察者Observer接口:主題通過調用update方法來通知各個實現Observer接口的觀察者們。

public interface Observer {
    
    public void update(float temp,float humidity,float pressure);
}
具體主題角色(Concrete Subject)

</pre><pre name="code" class="java">public class WeatherData implements Subject{
	
	private ArrayList observers;
	private float temperature;
	private float humidity;
	private float pressure;
	
	public WeatherData(){
		observers=new ArrayList();
	}

	@Override
	public void registerObserver(Observer o) {
		observers.add(o);
	}

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

	@Override
	public void notifyObservers() {
		for(int i=0;i<observers.size();i++){
			Observer observer=(Observer)observers.get(i);
			observer.update(temperature,humidity,pressure);
		}
	}
	
	public void measurementsChanged(){
		notifyObservers();
	}
	
	public void setMeasurements(float temperature,float humidity,float pressure){
		this.temperature=temperature;
		this.humidity=humidity;
		this.pressure=pressure;
		measurementsChanged();
	}

}

具體觀察者角色CurrentConditionDisplay

public class CurrentConditionsDisplay implements Observer{
	
	private float temperature;
	private float humidity;
	private float pressure;
	private Subject weatherData;
	
	public CurrentConditionsDisplay(Subject weatherData){
		this.weatherData=weatherData;
		weatherData.registerObserver(this);
	}
	
	@Override
	public void update(float temp, float humidity, float pressure) {
		this.temperature=temp;
		this.humidity=humidity;
		this.pressure=pressure;
		System.out.println("當前天氣狀態 :"+temperature+"度 , "+humidity+
				"溼度 和 "+pressure+"帕");
	}
}

具體觀察者角色StatisticsDisplay

public class StatisticsDisplay implements Observer{
	
	private float temperature;
	private float humidity;
	private float pressure;
	private Subject weatherData;

	public StatisticsDisplay(Subject weatherData){
		this.weatherData=weatherData;
		weatherData.registerObserver(this);
	}
	
	@Override
	public void update(float temp, float humidity, float pressure) {
		this.temperature=temp;
		this.humidity=humidity;
		this.pressure=pressure;
		System.out.println("統計天氣顯示 :"+temperature+"度 , "+humidity+
				"溼度 和 "+pressure+"帕");
	}

}


具體觀察者角色ForecastDisplay

public class ForecastDisplay implements Observer{
	
	private float temperature;
	private float humidity;
	private float pressure;
	private Subject weatherData;

	public ForecastDisplay(Subject weatherData){
		this.weatherData=weatherData;
		weatherData.registerObserver(this);
	}
	
	@Override
	public void update(float temp, float humidity, float pressure) {
		this.temperature=temp;
		this.humidity=humidity;
		this.pressure=pressure;
		System.out.println("預測天氣顯示 :"+temperature+"度 , "+humidity+
				"溼度 和 "+pressure+"帕");
	}

}

測試代碼
public class WeatherStation {
	
	public static void main(String []args){
		//首先建立一個主題WeatherData對象
		WeatherData weatherData=new WeatherData();
		//創建3個佈告板
		CurrentConditionsDisplay currentDisplay=new CurrentConditionsDisplay(weatherData);
		StatisticsDisplay statisticsDisplay=new StatisticsDisplay(weatherData);
		ForecastDisplay forecastDisplay=new ForecastDisplay(weatherData);
		//模擬氣象測量
		weatherData.setMeasurements(80,65, 30.4f);
	}

}

輸出結果
當前天氣狀態 :80.0度 , 65.0溼度 和 30.4帕
統計天氣顯示 :80.0度 , 65.0溼度 和 30.4帕
預測天氣顯示 :80.0度 , 65.0溼度 和 30.4帕


模式總結

       觀察者模式提供了一種對象設計,讓主題和觀察者之間松耦合。讓耦合的雙方都依賴於抽象,而不是依賴具體。從而使得各自的變化都不會影響另一邊的變化。 但是依賴關係並未完全解除,抽象通知者依舊依賴抽象的觀察者。因爲主題在調用觀察者的update方法時把內部的成員傳給了觀察者,而且對於不同的觀察者可能需要不同的參數。Java內置了觀察者模式,有推push和拉pull兩種。後續會使用java內置的觀察者模式來實現。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章