觀察者模式,是對象行爲型模式中的一種。觀察者模式的主旨是定義對象間的一種一對多的依賴關係,當一個對象的狀態發生改變時,所有依賴於它的對象都得到通知並被自動更新。
觀察者模式也可以稱爲發佈/訂閱模式,發佈者發佈信息,訂閱者獲取信息,訂閱了就能收到信息,沒訂閱就收不到信息。
觀察者模式提供了一種對象設計,讓主題和觀察者之間耦合度降得很低,爲什麼呢?關於觀察者的一切,主題只知道觀察者實現了Observer接口,並不需要觀察者具體的類是誰,做了什麼或者其他細節.
結構
觀察者模式的類結構關係如下:
可以看到,該模式包含四個角色
抽象被觀察者角色:也就是一個抽象主題,它把所有對觀察者對象的引用保存在一個集合中,每個主題都可以有任意數量的觀察者。抽象主題提供一個接口,可以增加和刪除觀察者角色。一般用一個抽象類和接口來實現。
抽象觀察者角色:爲所有的具體觀察者定義一個接口,在得到主題通知時更新自己。
具體被觀察者角色:也就是一個具體的主題,在集體主題的內部狀態改變時,所有登記過的觀察者發出通知。
具體觀察者角色:實現抽象觀察者角色所需要的更新接口,一邊使本身的狀態與製圖的狀態相協調。
JDK對觀察者模式的支持
Java中已經提供了觀察者模式的實現,我們不需要再定義觀察者和目標接口(被觀察者),可以繼承Observable類實現被觀察者目標對象,實現Observer接口完成具體的觀察者對象。而且Observable類中的addObserver、deleteObserver、notifyObservers等方法已經幫我們考慮了線程同步的問題,這樣更安全。
Observer:
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(Object arg) {
Object[] arrLocal;
synchronized (this) {
//判斷標識狀態是否改變,默認爲false
if (!changed)
return;
arrLocal = obs.toArray();
clearChanged();
}
for (int i = arrLocal.length-1; i>=0; i--)
((Observer)arrLocal[i]).update(this, arg);
}
/**
* Marks this <tt>Observable</tt> object as having been changed; the
* <tt>hasChanged</tt> method will now return <tt>true</tt>.
*/
protected synchronized void setChanged() {
changed = true;
}
具體被觀察者:
public class Subject extends Observable {
private int count=0;
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
//改變標識狀態
super.setChanged();
}
}
具體觀察者:
public class ObserverImpl implements Observer {
@Override
public void update(Observable o, Object arg) {
System.out.println("update.......");
//如果arg不爲null,被觀察者對象向觀察者推送主題的詳細信息
System.out.println(arg);
//從主題對象中"拉取"所需要的數據
Subject sub=(Subject)o;
System.out.println(sub.getCount());
}
}
測試類:
public class ObserverDemo {
public static void main(String[] args) {
Subject subject = new Subject();
Observer observer = new ObserverImpl();
subject.addObserver(observer);
subject.setCount(5);
subject.notifyObservers("calling");
}
}
//輸出
update.......
calling
5
推模型和拉模型
觀察者模式根據其側重的功能還可以分爲推模型和拉模型
推模型:被觀察者對象向觀察者推送主題的詳細信息,不管觀察者是否需要,推送的信息通常是主題對象的全部或部分數據。一般這種模型的實現中,會把被觀察者對象中的全部或部分信息通過update的參數傳遞給觀察者[update(Object obj) ]。
拉模型:被觀察者在通知觀察者的時候,只傳遞少量信息。如果觀察者需要更具體的信息,由觀察者主動到被觀察者對象中獲取,相當於是觀察者從被觀察者對象中拉數據。一般這種模型的實現中,會把被觀察者對象自身通過update方法傳遞給觀察者[update(Observable observable ) ],這樣在觀察者需要獲取數據的時候,就可以通過這個引用來獲取了。