學習觀察者模式,結合JavaJDK的內置觀察者模式代碼一塊兒學習package java.util;java
//不是抽象類,也不是接口
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) { /*從集合中提取每一個觀察者的代碼須要同步,可是通知觀察者的代碼不須要(不該該)。
潛在的最壞的結果是:
(1)新增的觀察者錯過了正在進行的通知
(2)未註冊的觀察者被通知到了
*/
if (!changed) //判斷標誌 return; arrLocal = obs.toArray(); //集合轉化成數組 clearChanged(); //標誌恢復成false 不須要通知更新 } for (int i = arrLocal.length-1; i>=0; i--) ((Observer)arrLocal[i]).update(this, arg); //每一個觀察者的update方法須要的參數是兩個,主題和參數 } /** * 清除所有的觀察者 */
public synchronized void deleteObservers() { obs.removeAllElements(); } /*將標誌改成true ,主題(被觀察者)發生改變了*/
protected synchronized void setChanged() { changed = true; } /*標誌更新爲false, 主題沒有變更,或者是變更了可是已經通知過了*/
protected synchronized void clearChanged() { changed = false; } /*查看是否發生改變(返回就是標誌)*/
public synchronized boolean hasChanged() { return changed; } /*返回觀察者的數量*/
public synchronized int countObservers() { return obs.size(); } }
這個類的主要構成要點:數組
一、包含全部觀察者的(空)的集合 + 對這個集合的管理操做(增減,查看數量)緩存
二、包含一個(是否變更)標誌 + 對這個標誌的管理操做(設置、查看)ide
三、向全部觀察者發送通知函數
繼續學習觀察者模式,JavaJDK中java.util.Observer源碼學習:學習
package java.util; /*這是觀察者的接口,關鍵點就是它有一個update方法,每當被通知修改時候,就是這個方法被調用 */ public interface Observer { void update(Observable o, Object arg); }
使用這兩個內置的觀察者模式類,參考方法:測試
(1)新建一個具體主題類繼承Observable, 不須要重寫它的任何方法,只要添加本身須要的業務邏輯: 設置傳遞的參數信息,發送消息的方法……this
惟一須要注意的是:兩種通知方式,參數的獲取方法不一樣spa
public class ConcreteSubjectA extends Observable { //保存數據 private String name; //設置參數信息 public void setInfo(String a){ this.name=a; } //觸發更新 public void sendNotify(){ setChanged(); //必須先要設置一下標誌,告知已經改了 //通知方式一;讓觀察者本身按需拉取(因此傳參是空) notifyObservers(); //通知方式二:直接把信息所有推送 notifyObservers(name); } //若是是拉取的通知方式,還要給出參數的獲取方法 public String getName() { return name; } }
(2) 新建觀察者類,實現Observer接口,這裏一般是有主題的引用的,這樣能夠本身完成註冊,註銷,和取數據設計
public class FirstObserver implements Observer { private Observable observable; public FirstObserver(Observable observable) { this.observable = observable; observable.addObserver(this);// 在構造的時候就能夠把本身註冊了,不用手動添加了,若是是改造已經存在的實體類,仍是須要手動添加 } @Override public void update(Observable o, Object arg) { if(o instanceof ConcreteSubjectA){ String name = ((ConcreteSubjectA) o).getName(); //拉取的通知方式,arg是null. 要本身獲取 //具體更新操做…… 略…… } } }
測試類:
public class Test { public static void main(String[] args) { ConcreteSubjectA ca=new ConcreteSubjectA(); FirstObserver firstObserver = new FirstObserver(ca); //構造時候註冊 ca.setInfo("我是新名字1"); ca.sendNotify(); //本身寫的通知方法,不是父類的notify ca.setInfo("我是新名字2"); ca.sendNotify(); ca.setInfo("我是新名字3"); ca.sendNotify(); } } /* 運行後輸出: 已經更新啦……我是新名字1 已經更新啦……我是新名字2 已經更新啦……我是新名字3 */
java.util.Observable存在的問題:
一、它是一個類,而不是一個接口,限制了它的複用。 想要用它就必須繼承它,那就不能再繼承其它類。
二、setChanged() 等方法是被保護的,除了繼承,沒法使用它。違反「多用組合,少用繼承」的設計原則。