觀察者模式是設計模式中常見的一種模式,他的思想猶如他的名字一樣,就是想建構一個觀察者觀察他所關注的主題,當主題發生變化了,就會通知觀察者。觀察者模式也叫釋出訂閱模式,這種設計模式用在了很多地方,比如zookeeper的節點觀察機制。
這裡我們建構一個如下模型,Subject<-AbstractSubject<-TopSubject 與 Observer<-Watcher,他們的關系如下圖所示:

通過java實作:
Observer.java
package com.xxx.design.watcher;
public interface Observer {
void update();
}
Watcher.java
package com.xxx.design.watcher;
/**
* 觀察者
*
*/
public class Watcher implements Observer {
private String name;
public Watcher(String name) {
this.name = name;
}
@Override
public void update() {
System.out.println("watcher "+name+" update state.");
}
}
Subject.java
package com.xxx.design.watcher;
public interface Subject {
void add(Observer observer);
void delete(Observer observer);
void notifyObserver();
void action();
}
AbstractSubject.java
package com.xxx.design.watcher;
import java.util.Enumeration;
import java.util.Vector;
public abstract class AbstractSubject implements Subject{
private Vector<Observer> obs = new Vector<Observer>();
@Override
public void add(Observer observer) {
obs.add(observer);
}
@Override
public void delete(Observer observer) {
obs.remove(observer);
}
@Override
public void notifyObserver() {
Enumeration<Observer> eles = obs.elements();
while(eles.hasMoreElements()){
eles.nextElement().update();
}
}
}
TopSubject.java
package com.xxx.design.watcher;
public class TopSubject extends AbstractSubject {
@Override
public void action() {
System.out.println("i am a subject,update now.");
notifyObserver();
}
public static void main(String[] args) {
Subject subject = new TopSubject();
subject.add(new Watcher("aa"));
subject.add(new Watcher("bb"));
subject.add(new Watcher("cc"));
subject.action();
}
}
運作程式,列印結果如下:
i am a subject,update now.
watcher aa update state.
watcher bb update state.
watcher cc update state.
觀察者需要注意的是:避免循環引用,如果是順序執行,考慮采用異步實作,避免因為一個處理異常導緻整個系統卡殼。另外,現在java.util包中api已經提供了觀察者模式的實作。我們可以利用Observable類和Observer接口來實作一個觀察者模式:
Subscribe.java
package com.xxx.design.watcher.jdk;
import java.util.Observable;
import java.util.Observer;
public class Subscribe implements Observer {
private String name;
public Subscribe(String name){
this.name = name;
}
public void add(Observable o){
o.addObserver(this);
}
@Override
public void update(Observable o, Object arg) {
System.out.println(name+" 收到通知:"+((Publish)o).getData());
}
}
Publish.java
package com.xxx.design.watcher.jdk;
import java.util.Observable;
public class Publish extends Observable {
private String data = "";
public String getData() {
return data;
}
public void setData(String data) {
if(!this.data.equals(data)){
this.data = data;
setChanged();
}
notifyObservers();
}
public static void main(String[] args) {
Publish publish = new Publish();
Subscribe subscribe = new Subscribe("aaa");
subscribe.add(publish);
Subscribe subscribe2 = new Subscribe("bbb");
subscribe2.add(publish);
publish.setData("start");
publish.setData("end");
}
}
運作程式,列印資訊如下:
bbb 收到通知:start
aaa 收到通知:start
bbb 收到通知:end
aaa 收到通知:end