最近在看《深刻淺出Nodejs》,看完了第三章異步IO,以爲觀察者模式在Node中十分重要因而找了幾篇博客學習了一下觀察者模式。html
主要的參考博客:
《JAVA與模式》之觀察者模式——java_my_life
java:從消息機制談到觀察者模式——luoweifujava
觀察者模式是對象的行爲模式,又叫發佈-訂閱(Publish/Subscribe)模式、模型-視圖(Model/View)模式、源-監聽器(Source/Listener)模式或從屬者(Dependents)模式。
觀察者模式定義了一種一對多的依賴關係,讓多個觀察者對象同時監聽某一個主題對象。這個主題對象在狀態上發生變化時,會通知全部觀察者對象,使它們可以自動更新本身。數組
偷懶直接拿了別人的圖:
異步
觀察者模式能夠分爲拉模型和推模型兩種:ide
//Observer.java public interface Observer { void update(String newState); }
//Observable.java public abstract class Observable { private ArrayList<Observer> observerList = new ArrayList<>(); public void addObserver(Observer o) { observerList.add(o); } public void removeObserver(Observer o) { observerList.remove(o); } public void nodifyObservers(String newState) { for(Observer observer : observerList) { observer.update(newState); } } }
//ConcreteObserver.java public class ConcreteObserver implements Observer { public ConcreteObserver(Observable o) { o.addObserver(this); } @Override public void update(String newState) { System.out.println("狀態已更新:" + newState); } }
//ConcreteObservable.java public class ConcreteObservable extends Observable { private String state = ""; public String getState() { return state; } public void setState(String state) { if(!this.state.equals(state)) { this.state = state; this.nodifyObservers(state); } } }
//Client.java public class Client { public static void main(String[] args) { ConcreteObservable concreteObservable = new ConcreteObservable(); ConcreteObserver concreteObserver = new ConcreteObserver(concreteObservable); concreteObservable.setState("神清氣爽"); } } /*OUTPUT: 狀態已更新:神清氣爽 */
Java提供的觀察者模式應該就是一種拉模型(我的理解),下面的代碼刪去了一些源碼中的註釋。學習
//Observer.java package java.util; public interface Observer { void update(Observable o, Object arg); }
//Observable.java package java.util; public class Observable { private boolean changed = false; private Vector<Observer> 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) { /* We don't want the Observer doing callbacks into * arbitrary code while holding its own Monitor. * The code where we extract each Observable from * the Vector and store the state of the Observer * needs synchronization, but notifying observers * does not (should not). The worst result of any * potential race-condition here is that: * 1) a newly-added Observer will miss a * notification in progress * 2) a recently unregistered Observer will be * wrongly notified when it doesn't care */ 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(); } }
須要注意的是notifyObservers()這個方法中,從Vector中取出Observers並放在一個Object數組中,這個操做是在synchronized塊中的。可是調用Observer的update()沒有在synchronized塊中(猜測這個地方是爲了防止Observer的update()也須要鎖住Observable而形成死鎖,也許也有防止被Observa被鎖住太長時間的目的),所以會有競爭的風險this
Watched.java.net
public class Watched extends Observable { private String data = ""; public String getData() { return data; } public void setData(String data) { if(!this.data.equals(data)){ this.data = data; setChanged(); } this.notifyObservers(); } }
Watcher.javacode
public class Watcher implements Observer{ public Watcher(Observable observable) { observable.addObserver(this); } @Override public void update(Observable o, Object arg) { System.out.println("狀態已改變:" + ((Watched)o).getData()); } }
DemoClient.javaserver
public class DemoClient { public static void main(String[] args) { Watched watched = new Watched(); Watcher watcher = new Watcher(watched); watched.setData("好——像有點不對勁!"); } } /*OUTPUT: 狀態已改變:好——像有點不對勁! */