Header First設計模式學習筆記——觀察者模式

問題引入java

        生成一個公告板顯示當時的天氣情況,當天氣情況發生改變的時候公告板能夠實時的更新。
編程

模式定義ide

        定義對象之間的一對多的依賴,當一個對象改變狀態時,它的全部依賴者都會自動收到通知並自動更新。this

認識模式spa

        該模式在生活中是很常見的。想一想生活中的各類各樣的檢測系統,報警系統,一旦有重要事件發生時,有關係統總能及時的收到通知,這就是觀察者模式。
.net

問題解決code

        關於觀察者模式,java實際上給了咱們內置的支持(能夠看出該模式仍是很經常使用的吧!)可是咱們常常會本身實現。爲何呢?咱們後面會給出答案。
orm

        被觀察者咱們稱之爲主題(Subject),相應的有觀察者(Observer)。
server

1、自定義實現對象

      1)  Subject,Observer咱們都定義爲接口

package my.oschina.net.design.observer.owndesign;

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

public interface Observer {
	void update(Subject sub);
}

    2)實現Subject和Observer接口(主題與觀察者的實現)    

        a)主題實現

package my.oschina.net.design.observer.finaldesign;

import java.util.ArrayList;

public class WeatherData implements Subject{
	
	//被觀測的指標數據
	private float temp;
	private float humidity;
	private float pressure;
	
	//維護一個訂閱過的Observer列表
        private ArrayList<Observer> Observers;
	
	public WeatherData()
	{
		this.Observers = new ArrayList<Observer>();
	}

	@Override
	//增長Observer
	public void registerObserver(Observer o) {
		// TODO Auto-generated method stub
		Observers.add(o);		
	}

	@Override
	//移除部分Observer
	public void removeObserver(Observer o) {
		// TODO Auto-generated method stub
		int i = Observers.indexOf(o);
		if(i != -1)
			Observers.remove(Observers.indexOf(o));		
	}
	
	@Override
	//通知訂閱過的Observer
	public void notifyObserver() {
		// TODO Auto-generated method stub
		for(Observer o : Observers)
		{
			o.update(this);
		}
	}
	
	public void setStatus(float temp, float humidity, float pressure)
	{
		this.temp = temp;
		this.humidity = humidity;
		this.pressure = pressure;	
		
		statusChanged();
	}
	
	public void statusChanged()
	{
		notifyObserver();
	}
	
	float getTemp()
	{
		return temp;
	}
	
	float getHumidity()
	{
		return humidity;
	}
	
	float getPressure()
	{
		return pressure;
	}	
}

          b)觀察者實現

package my.oschina.net.design.observer.finaldesign;

public class CurrentConditionDisplay implements Observer,Display{
	
	//接收被觀測者發過來的數據
	private float temp;
	private float humidity;
	private float pressure;
	//保存這個主題對象,可能後續有退訂的需求
	private WeatherData weatherData;
	
	public CurrentConditionDisplay(WeatherData weahterdata)
	{
		this.weatherData = weahterdata;
		weatherData.registerObserver(this);
	}
	
	@Override
	public void update(Subject sub) {
		// TODO Auto-generated method stub
		
		if(sub instanceof WeatherData)
		{
			WeatherData weatherdata = (WeatherData)sub;
			this.temp = weatherdata.getTemp();
			this.humidity = weatherdata.getHumidity();
			this.pressure = weatherdata.getPressure();
		}
		
		display();
	}

	@Override
	public void display() {
		// TODO Auto-generated method stub
	System.out.println("Temp --> " + temp + "humidity --> " +humidity + "pressure -->" + pressure);
	}

}

        3)Test一下

package my.oschina.net.design.observer.finaldesign;

public class ObserverTest1 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
	    WeatherData weatherdata = new WeatherData();
	    
		CurrentConditionDisplay cc = new CurrentConditionDisplay(weatherdata);
		
		weatherdata.setStatus(12, 12, 12);
		weatherdata.setStatus(13, 13, 13);
		weatherdata.setStatus(14, 14, 14);		
	}
}

        4)結果截圖

2、java內置實現

        在java的java.util 包(pac1kage)中包含了最基本的Observable類(可觀察,經過繼承方式得到其方法和屬性)Observer接口(觀察),對你沒有看錯,我也沒有寫錯,的確是Observable類Observer接口,他們相似與咱們上述本身定義的Subject和Observer接口,因爲是java內置,有的時候使用它們的話真的是挺簡單的,由於有好多的功能java自己已經爲咱們寫好了!

        其實這裏你已經能夠明白這種內置實現的弊端了,對就是由於Observable是個類!在java中只支持單繼承,因此啊,這就限制了繼承他的類使用的靈活性!

java內置的不一樣

    a)關於主題對象

        當咱們自定義觀察者的時候當須要通知觀察者的時候咱們直接調用notifyO不servers()方法便可, 可是java內置的方法不是這樣的,咱們須要兩步走:

                1>調用setChanged()方法,標記狀態已改變;

                2>調用notifyObserver()方法,完成通知的工做。

 深刻-------->setChanged()

                咱們來看看Observable內部的實現

   setChanged()
   {
       cahnged = true;
   }
  
   notifyObservers(Object arg)
   {
       if(cahnged)
       {
           for every obsrver on the list
           {
               call update(this, arg)
           }
           cahngd = false;
       }
   }
   
    notifyObservers()
    {
        notifyObservers(null)
    }

         看到這裏有人可能要問了:爲何要設置一個標誌呢???仔細想一想,假設你是公司老總,天天要批一系列文件,好了,如今祕書送來一份文件你批了,一分鐘沒到,又有新的文件產生了,祕書又送了過來,而後。。。而後。。。你受得了嗎?你可能會對祕書說:小李啊,這個文件你給我每50份一批給我送過來,我一併批閱!有時候咱們並不但願被觀察者有一絲的變化立刻就通知咱們,咱們能夠等被觀察者達到必定的程度的時候(好比說等溫度上升5℃之內沒必要通知系統,一旦超過5℃就通知系統!)再通知咱們,你能夠想一想這樣好處不少!因此當達到標準,咱們須要通知觀察者的時候調用setChanged()方法還真是不錯的哦!

    b)關於觀察者

                update的方法略有不一樣update(Observable o, Object arg),第一個參數是主題自己,第二個參數爲傳入notifyObserver()的數據對象,沒有爲空。這裏就來決定是由被觀察者push數據,仍是有觀察者本身pull數據。

代碼走起         

1)被觀察者實現(注意import相應的package)

package my.oschina.net.design.observer.javautil;

import java.util.Observable;
import java.util.Observer;
/**
 * 這種方式有一個弊端就是說Observable是一個 類而不是一個接口所以它限制了這個類的使用
 * @author Eswin
 *
 */
public class WeatherData extends Observable{
	
	//被觀測的指標數據
	private float temp;
	private float humidity;
	private float pressure;

	public WeatherData(){}
	
	public void setStatus(float temp, float humidity, float pressure)
	{
		this.temp = temp;
		this.humidity = humidity;
		this.pressure = pressure;	
		
		statusChanged();
	}
	
	public void statusChanged()
	{
		setChanged();
		notifyObservers();
	}
	
	public float getTemp()
	{
		return temp;
	}
	
	public float getHumidity()
	{
		return humidity;
	}
	
	public float getPressure()
	{
		return pressure;
	}

	
}

2)觀察者實現

package my.oschina.net.design.observer.javautil;

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

import my.oschina.net.design.observer.owndesign.Display;

public class CurrentConditionDisplay implements Observer, Display{

	private float temp;
	private float humidity;
	private float pressure;
	
	private Observable observable;
	
	public CurrentConditionDisplay(Observable observable)
	{
		this.observable = observable;
		observable.addObserver(this);
		
	}
	
	@Override
	public void update(Observable o, Object arg) {
		// TODO Auto-generated method stub
		if(o instanceof WeatherData)
		{
			WeatherData weatherdata = (WeatherData)o;
			this.temp = weatherdata.getTemp();
			this.humidity = weatherdata.getHumidity();
			this.pressure = weatherdata.getPressure();
		}
		
		display();
		
	}

	@Override
	public void display() {
		// TODO Auto-generated method stub
		System.out.println("Temp --> " + temp + "humidity --> " +humidity + "pressure -->" + pressure);
	}

}

3)Test一下

package my.oschina.net.design.observer.javautil;

public class ObserverTest2 {
	public static void main(String[] args) {
		// TODO Auto-generated method stub		
	        WeatherData weatherdata = new WeatherData();
	        	    
		CurrentConditionDisplay cc = new CurrentConditionDisplay(weatherdata);
		
		weatherdata.setStatus(12, 12, 12);
		weatherdata.setStatus(13, 13, 13);
		weatherdata.setStatus(14, 14, 14);
	}
}

 4)結果截圖

模式延伸

    其實咱們咱們在編程的過程當中有不少時候都運用到了觀察者模式,想一想Swing,還有JavaBean,還有RMI。

模式建議

    1)要注意Observable這個類所帶來的問題;

    2)有必要的話本身實現Observable也就是主題,很簡單(三個方法實現就能夠了)。

相關文章
相關標籤/搜索