Java設計模式(十)

rel="File-List" href="file:///C:%5CDOCUME%7E1%5CADMINI%7E1%5CLOCALS%7E1%5CTemp%5Cmsohtmlclip1%5C01%5Cclip_filelist.xml"> rel="themeData" href="file:///C:%5CDOCUME%7E1%5CADMINI%7E1%5CLOCALS%7E1%5CTemp%5Cmsohtmlclip1%5C01%5Cclip_themedata.thmx"> rel="colorSchemeMapping" href="file:///C:%5CDOCUME%7E1%5CADMINI%7E1%5CLOCALS%7E1%5CTemp%5Cmsohtmlclip1%5C01%5Cclip_colorschememapping.xml">

Java設計模式(十)

------------觀察者模式

引入

我們這裏利用《Head.First.設計模式》中的那個氣象站的經典的例子坐引。

我們需要建立一個該氣象站,它必須建立在我們專利申請中的WeatherD ata對象上,由WeatherData對象負責追蹤目前的天氣狀況(溫度、溼度、氣壓)。我們還要建立一個應用,有三種佈告板,分別顯示目前的狀況、氣象統計及簡單的預報。當WeatherObject對象獲得最新的測量數據時,三種佈告板必須實時更新。

而且,我們還希望它是一個可以擴展的氣象站,也就是允許其他開發人員可以寫出自己的氣象佈告板,並插入此應用中。

好了,下面的例子我們都將圍繞這個例子進行。

定義與角色

定義

觀察者模式定義了對象之間的一對多依賴,這樣一來,當一個對象改變狀態時,它的所有依賴者都會收到通知並自動更新。

角色

抽象主題角色

public interface Subject {

 

       public void addObserver(Observer o);

 

       public void removeObserver(Observer o);

 

       public void notifyObserver();

 

}

 

具體主題角色

public class WeatherData implements Subject {

       List<Observer> listeners = new ArrayList<Observer>();

 

       public int getTemperature() {

              return 0;

       }

 

       public double getHumidity() {

              return 0.53;

       }

 

       int getPressure() {

              return 30;

       }

       // 對外暴露接口

       public void measurementsChanged() {

              this.notifyObserver();

       }

       @Override

       public void addObserver(Observer o) {

              // TODO Auto-generated method stub

              listeners.add(o);

       }

       @Override

       public void notifyObserver() {

              // TODO Auto-generated method stub

              int t = this.getTemperature();

              double h = this.getHumidity();

              int p = this.getPressure();

              for (int i = 0; i < listeners.size(); i++) {

                     Observer listener = listeners.get(i);

                     listener.onWebtherChange(t, h, p);

              }

       }

       @Override

       public void removeObserver(Observer o) {

              // TODO Auto-generated method stub

              listeners.remove(o);

       }

}

 

抽象觀察者角色

public interface Observer {

 

       public void onWebtherChange(int t, double h, int p);

 

}

 

具體觀察者角色

public class HWeatherPanel implements Observer {

 

       public WeatherData data;

 

       public HWeatherPanel(WeatherData data) {

              this.data = data;

              data.addObserver(this);

       }

 

       @Override

       public void onWebtherChange(int x, double h, int p) {

              // TODO Auto-generated method stub

              System.out.println("更新溼度面板,最溼度是 " + h);

       }

 

}

public class PWeatherPanel implements Observer {

       public WeatherData data;

 

       public PWeatherPanel(WeatherData data) {

              this.data = data;

              data.addObserver(this);

       }

 

       @Override

       public void onWebtherChange(int x, double h, int p) {

              // TODO Auto-generated method stub

              System.out.println("更新壓力面板,最新壓力是 " + p);

       }

 

}

public class TWeatherPanel implements Observer {

       public WeatherData data;

 

       public TWeatherPanel(WeatherData data) {

              this.data = data;

              data.addObserver(this);

       }

 

       @Override

       public void onWebtherChange(int x, double h, int p) {

              // TODO Auto-generated method stub

              System.out.println("更新溫度面板,最新溫度是 " + x);

       }

 

}

 

客戶調用

public class MyTest {

 

       /**

        * @param args

        */

       public static void main(String[] args) {

              // TODO Auto-generated method stub

              WeatherData data = new WeatherData();

              HWeatherPanel hp = new HWeatherPanel(data);

              PWeatherPanel pp = new PWeatherPanel(data);

              TWeatherPanel tp = new TWeatherPanel(data);

 

              data.measurementsChanged();

       }

 

}

打印結果:

          更新溼度面板,最溼度是 0.53

          更新壓力面板,最新壓力是 30

          更新溫度面板,最新溫度是 0

 

Java中內置的觀察者模式

到目前爲止,我們已經從無到有地完成了觀察者模式,但是,JavaAAPI有內置的觀察者模式。java.util包(package)內包含最基本的Observer接口與Observable類,這和我們的Subject接口與Observer接口很相似。Observer接口與Observable類使用上更方便,因爲許多功能都已經事先準備好了。

使用

接口 Observer

一個可在觀察者要得到 observable 對象更改通知時可實現 Observer 接口的類。

update(Observable o, Object arg)

很顯然 這個Observer接口就是對應我們自己實現中的Observer接口,update(Observable o, Object arg)方法就對應我們的onWebtherChange(int t, double h, int p)方法這與我們的想法甚至名稱都是一致的。

Observable

 

方法摘要

 void

addObserver(Observer o)
如果觀察者與集合中已有的觀察者不同,則向對象的觀察者集中添加此觀察者。

protected  void

clearChanged()
指示對象不再改變,或者它已對其所有的觀察者通知了最近的改變,所以 hasChanged 方法將返回 false

 int

countObservers()
返回 Observable 對象的觀察者數目。

 void

deleteObserver(Observer o)
從對象的觀察者集合中刪除某個觀察者。

 void

deleteObservers()
清除觀察者列表,使此對象不再有任何觀察者。

 boolean

hasChanged()
測試對象是否改變。

 void

notifyObservers()
如果 hasChanged 方法指示對象已改變,則通知其所有觀察者,並調用 clearChanged 方法來指示此對象不再改變。

 void

notifyObservers(Object arg)
如果 hasChanged 方法指示對象已改變,則通知其所有觀察者,並調用 clearChanged 方法來指示此對象不再改變。

protected  void

setChanged()
標記此 Observable 對象爲已改變的對象;現在 hasChanged 方法將返回 true

 

由上表可以看出Observable類對應我們自己實現中的Subject接口,由於它是一個類,對於想要擴展的朋友就顯得無能爲力了,但是對於一般的觀察者應用已經足夠使了。

區別

我們不難發現,這個函數表中多個一個change的概念(setChanged()hasChanged()clearChanged())它的引入是爲了在更新觀察者時,有更多的彈性,你可以更適當地通知觀察者。比方說,如果沒有setChanged()方法,我們的氣象站測量是如此敏銳,以致於溫度計讀數每十分之一度就會更新,這會造成WeatherData對象持續不斷地通知觀察者,我們並不希望看到這樣的事情發生。如果我們希望半度以上才更新,就可以在溫度差距到達半度時,調用setChanged(),進行有效的更新。你也許不會經常用到此功能,但是把這樣的功能準備好,當需要時馬上就可以使用。總之,你需要調用setChanged(),以便通知開始運轉。如果此功能在某些地方對你有幫助,你可能也需要clearChanged()方法,將changed狀態設置回false。另外也有一個hasChanged()方法,告訴你changed標誌的當前狀態。

總結

優勢

主題對象與觀察者對象之間的松耦合,主題對象只知道Obserser接口,並不關誰實現了該接口以及怎麼實現的,一旦有新類型觀察者出現,我們只要把它註冊到主題中就可以了,不用修改任何代碼。

主要程序設計應用

這種設計模式廣泛用於數據或狀態的變化引起的界面刷新工作。

比如一個股票數據(價格)發生變化,可能會影響幾個視圖的更新(實時圖,表圖,甚至要入庫操作。。。),我們就需要把這幾個視圖和操縱數據庫的類作爲觀察者,註冊到相應主題中去。

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