JDK 中的Observer設計模式

1.Observer設計模式概要

   Observer設計模式在GOF裏屬於行爲設計模式。JDK裏提供的observer設計模式的實現由java.util.Observable類和java.util.Observer接口組成。從名字上可以清楚的看出兩者在

Observer設計模式中分別扮演的角色:Observer是觀察者角色,Observable是被觀察目標(subject)角色。

   Observable是一個封裝subject基本功能的類,比如註冊observer(attach功能),註銷observer(detatch功能)等。這些功能是任何一個扮演observerable角色的類都需要實現的,

從這一點上來講,JDK裏將這些通用功能專門封裝在一個類裏,顯得合情合理。通常情況下,我們的類只要從Observerable類派生就可以稱爲observerable角色類,使用非常簡單。

2.使用observer設計模式存在的困難

  但我們不得不注意到,在項目實際開發當中,情況往往要複雜得多。java不支持多繼承特性在很多時候是阻礙我們使用observer設計模式的絆腳石。比如說,我們設計的一個類已經是某

個類的派生類,在這種情況下同時想讓它扮演observerable角色將變得麻煩。如何實現“多繼承”的效果是擺在我們面前的一大難題。下面我們首先分析一下Observable類。

  3.Observable類的“觸發-通知”原理

  Observable必須“有變化”才能觸發通知observer這一任務,這是它的本質體現。查看源碼便可知一二。Observerable部分源碼如下:
 //……省略……
   private boolean changed = false;

   //……省略……

   public void notifyObservers(Object arg){
    //……省略……
     Object[] arrLocal;
     synchronized (this){
      //……省略……
      if (!changed)
        return;
       arrLocal = obs.toArray();
       clearChanged();
    }

   //……省略……
   protected synchronized void setChanged() {
     changed = true;
   }
 
   protected synchronized void clearChanged() {
     changed = false;
   }

    正如上所示,在notifyObservers(Object arg)方法裏if(!changed) return;語句告訴我們,若changed屬性值爲false,將直接返回,根本不會觸發通知操作。並且我們注意到changed屬

性被初始化爲false,這將意味着如果我們不主動設置changed屬性爲true,將不會有任何變化,也就是說根本起不到“通知”作用。因此,設置changed屬性的值是我們應用jdk observer 

設計模式的關鍵所在。

    那麼如何才能設置changed屬性呢?從源碼可以看出,唯一的入口是通過setChanged()。下面我們分析一下changed屬性及相關的方法setChanged()和clearChanged()。

4.Observable類的分析

  細心的讀者可能會注意到Observable中跟changed屬性有關的兩個方法setChanged()和clearChanged(),它們的修飾符都是protected,而不是public。但這樣是否有其必要性和合理性?

答案是肯定的。在前面的分析中,已經提到,setChanged()方法是設置changed的唯一入口,它的修飾符定義爲protected,就意味着不通過Observable定義的對象,設置changed屬性將變得不

可能。從這個意義上說,要想應用observer設計模式,必須繼承Observable類方可。

    但是,爲什麼不能定義成public?這似乎難以理解。因爲定義成public,我們不就可以很方便地設置changed屬性的值嗎?爲了弄清楚這個問題,我們還是看一下Observable裏的相關的代

碼:

  //……省略……
  public void notifyObservers(Object arg) {
  //……省略……
   for (int i = arrLocal.length-1; i>=0; i--)
    ((Observer)arrLocal[i]).update(this, arg);
  }
    
  這段代碼表達的意思是找出所有已註冊的Observer,再逐個通過調用Observer的update(Observable,Object)方法進行“通知”。我們看到,update方法的第一個參數是this,我們同時還

注意到,這段代碼是Observable類裏的代碼。這就相當於是在一再強調,發出“通知”的,必須是observable(Observable類或者其派生類),其它任何類都不行。這就意味着我們的

observable類繼承Observable類是必要的,因爲如果不繼承,而採用組合的話,將無法保證能傳遞好this。換句話說,採用組合的方式使用Observable類,將變得幾乎沒有任何意義。同時,

修飾符定義爲protected,可以確保是在Observable裏進行觸發通知的,不會在其它任何地方進行通知,這顯得內斂性很強。如果將setChanged()修飾符定義爲public,將無法保證正確“傳

遞this”的硬性要求,即不符合“只有observalbe才能直接或間接通知observer”這一observable設計模式的硬性要求。由此我們可見一斑,jdk的很多理念的思想性是多麼的強。

  5.解決使用observer設計模式存在的困難

  藉助adapter設計模式和java支持多接口特性基本可以解決“多繼承”問題。基本思想是結合繼承/實現和組合來達到效果。在上面的分析中已經知道,Observable類必須繼承使用,不能

組合使用,因此只需要將需扮演成observerable角色的類裝扮成adapter角色,將該類原繼承的類裝扮成adapter角色即可。示例代碼如下:

  //欲充當observable角色的類的原來的代碼:
  public class MyObject extends BaseObject {
   public MyObject() {
    public void method1(){}
   }
  }

  //充當observable角色後的代碼:
  public class MyObject extends Observable {
   private BaseObject baseObject = null;
    public MyObject(BaseObject baseObject) {
     this.baseObject = baseObject;
    }
  }

 

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