設計模式 - 觀察者模式

概述


很早以前,當一個對象的行爲依賴於另一個對象的狀態時,只能開啓一個線程不斷的監聽對象所依賴的狀態。比如通過Callable線程的call()方法獲取線程的返回值。當調用Future接口的get()方法時,程序會阻塞在那裏,直到拿到線程的執行結果。這種方法雖然可行,但是會給系統帶來額外的線程開銷,在一個複雜的系統中,這種開銷不可小視。觀察者模式可以在單線程中使某一對象及時得知自身所依賴的狀態的變化。以下是觀察者模式經典結構圖:

ISubject是被觀察對象,可以增加或刪除觀察者。IObserver是觀察者,它監聽被觀察者的狀態變化。當ISubject狀態發生變化時,會通過inform()方法通知觀察者。
觀察者模式角色如下:
  • 主題接口:被觀察的對象,接口定義了新增觀察者、刪除觀察者和通知觀察者等方法(ISubject)。
  • 具體主題:實現主題接口中的方法。當其狀態改變時,它將會通過這個變化通知觀察者(ConcreteSubject)。
  • 觀察者接口:定義了觀察者的基本方法。當依賴狀態改變時,主題接口會調用觀察者的update方法(IObserver)。
  • 具體觀察者:實現觀察者接口的update方法(ConcreteObserver)。
簡單來說,就是被觀察者對象實現主題接口,觀察者對象實現觀察者接口。仔細觀察你會發現,觀察者模式其實就是對Java回調機制的運用。

代碼示例

主題接口:
package observer;

public interface Isubject{
	// 添加觀察者
	public void attach(IObserver observer);
	// 刪除觀察者
	public void detach(IObserver observer);
	// 通知觀察者
	pubic void inform();
}
觀察者接口:
package observer;

public interface IObserver{
	// 更新觀察者
	public void update(Event event);
}
具體主題:
package observer;

pubic class ConcreteSubject implements ISubject {
	List<IObserver> observers = new ArrayList<>();
	
	public void attach(IObserver observer){
		observers.add(observer);
	}

	public void detach(IObserver observer){
		observers.remove(observer);
	}
	
	public void inform(){
		Event event = new Event();
		for(IObserver observer : observers){
			observer.update(event);
		}
	}
}
具體觀察者:
<span style="font-size:14px;">package observer;

public class ConcreteObserver implements IObserver{
	public void update(Event event){
		System.out.println("Received information.");
	}
}</span>
JDK內置的觀察者

JDK中已經實現了一套觀察者模式。在java.util包中,包括java.util.Observable類和java.util.Observer接口,它們的關係接口圖如下:

在java.util.Observable類中,已經實現了主要功能,如增加觀察者,刪除觀察者和通知觀察者,開發者可以直接繼承Observable類使用這些功能。java.util.Observer接口是觀察者接口,觀察者對象需要實現Observer接口並實現update方法。
下面是Observable類的內部實現:
package java.util;

public class Observable {
  private boolean changed = false;
  private Vector obs;

  /**
   * 創建被觀察者時就創建一個它持有的觀察者列表,注意,這個列表是需要同步的。
   */
  public Observable() {
    obs = new Vector();
  }

  /**
   * 添加觀察者到觀察者列表中去
   */
  public synchronized void addObserver(Observer o) {

    if (o == null)
      throw new NullPointerException();
    if (!obs.contains(o)) {
      obs.addElement(o);
    }
  }

  /**
   * 刪除一個觀察者
   */ 
  public synchronized void deleteObserver(Observer o) {
    obs.removeElement(o);
  }

  public void notifyObservers() {
    notifyObservers(null);
  }

  /**
   * 通知操作,即被觀察者發生變化,通知對應的觀察者進行事先設定的操作,這個方法接受一個參數,這個參數一直傳到觀察者裏,以供觀察者使用
   */ 
  public void notifyObservers(Object arg) {
    Object[] arrLocal;
    synchronized (this) {
      if (!changed)
        return;
      arrLocal = obs.toArray();
      clearChanged();
    }
    for (int i = arrLocal.length-1; i>=0; i--)
      ((Observer)arrLocal[i]).update(this, arg);
  }

  public synchronized void deleteObservers() {
    obs.removeAllElements();
  }

  protected synchronized void setChanged() {
    changed = true;
  }

  protected synchronized void clearChanged() {
    changed = false;
  }


  public synchronized boolean hasChanged() {
     return changed;
  }

  public synchronized int countObservers() {
    return obs.size();
  }
}








發佈了31 篇原創文章 · 獲贊 19 · 訪問量 10萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章