Java設計模式-觀察者模式
觀察者模式定義了一種一對多的依賴關係,讓多個觀察者物件同時監聽某一個主題物件,這個主題物件在狀態上發生變化時,會通知所有觀察者物件,讓他們能夠自動更新自己。
觀察者模式的組成
觀察者模式主要由以下四個角色組成,分別是抽象主題角色、抽象觀察者角色、具體主題角色、具體觀察者角色。
抽象主題角色
把所有觀察者物件的引用儲存在一個集合中,每個抽象主題角色都可以有任意數量的觀察者,抽象主題提供一個介面,可以增加和刪除觀察者角色,一般用一個抽象類或介面來實現。
抽象觀察者角色
為所有具體的觀察者定義一個介面,在得到主題的通知時更新自己。
具體主題角色
在具體主題內部狀態改變時,給所有登記過的觀察者發出通知,具體主題角色通常用一個子類實現。
具體觀察者角色
該角色實現抽象觀察者角色所要求的更新介面,以便使本身的狀態與主題的狀態相協調,如果需要,具體觀察者角色可以有一個指向具體主題角色的引用,通常用一個子類實現
觀察者模式的程式碼示例
抽象主題角色:
public interface AbstractSubject { public void addObserver(AbstractObserver observer); public void removeObserver(AbstractObserver observer); public void notification(); } 複製程式碼
具體主題角色:
public class ConcreteSubject implements AbstractSubject { List<AbstractObserver> list = new ArrayList<AbstractObserver>(); @Override public void addObserver(AbstractObserver observer) { list.add(observer); } @Override public void removeObserver(AbstractObserver observer) { list.remove(observer); } # 狀態改變了,所有觀察者更新自己的介面 @Override public void notification() { for (AbstractObserver abstractObserver : list) { abstractObserver.update(); } } } 複製程式碼
抽象觀察者角色:
public interface AbstractObserver { public void update(); } 複製程式碼
測試類
class Client { public static void main(String[] args) { #生成一個主題角色 AbstractSubject subject = new ConcreteSubject(); #為主題角色增加觀察者物件,這裡採用匿名內部類的方式,與AWT程式設計裡的安裝監聽器類似 subject.addObserver(new AbstractObserver() { @Override public void update() { System.out.println("A同學您的APP需要更新"); } }); subject.addObserver(new AbstractObserver() { @Override public void update() { System.out.println("B同學您的APP需要更新"); } }); subject.addObserver(new AbstractObserver() { @Override public void update() { System.out.println("C同學您的APP需要更新"); } }); subject.notification(); } } 複製程式碼
Java內建的觀察者模式框架
java內建觀察者模式框架提供了類Observable 與介面Observer :
類Observable 對應抽象主題角色,內部維護Vector集合來儲存具體觀察者角色 介面Observer 對應抽象觀察者角色
根據上面在描述,如何基於Java內建的觀察者模式框架實現一個觀察者模式呢?
- 寫一個類(具體主題角色)繼承Observable(抽象主題角色),只需要寫一個change方法即可 (該方法作用是通知已註冊的具體主題角色更新自己)
- 寫一個類(具體觀察者角色)實現Observer(抽象觀察者角色),只需要實現方法update(Observable o, Object arg)即可
- 寫一個測試類進行測試
程式碼實戰演示
具體主題角色:
public class Watched extends Observable { #狀態改變的時候呼叫已註冊的觀察者的update方法,讓它們更新自己 public void count(int number) { for (; number >= 0; number--) { try { Thread.sleep(1000); #告知變更 setChanged(); #通知所有與我相關的Observer notifyObservers(number); } catch (Exception e) { e.printStackTrace(); } } } } 複製程式碼
具體觀察者角色:
public class Watcher implements Observer { #當主題角色事件觸發時,會呼叫所有已註冊的具體觀察者角色的update方法 @Override public void update(Observable o, Object arg) { int number = (Integer) arg; System.out.println(number); } } 複製程式碼
測試類:
public class Client { public static void main(String[] args) { #建立主題角色 Watched watched = new Watched(); #建立觀察者角色 Observer watcher1 = new Watcher(); #自實現 Observer watcher2 = new Observer() { @Override public void update(Observable o, Object arg) { int number = (Integer) arg; if (0 == number) { System.out.println("done"); } } }; watched.addObserver(watcher1); watched.addObserver(watcher2); watched.count(10); } } 複製程式碼
java觀察者模式框架的總結
- 被觀察者要繼承Observable 類
- 被觀察者通知觀察者時,也就是呼叫notifyObservers方法時一定要先呼叫setChanged()方法 ,該方法作用是將物件裡面的changed這個boolean變數設為true,因為notifyObservers要首先檢查該變數是否為true,如果為false就不執行而直接返回了。
-
Observable類中兩個過載的notifyObservers方法,帶引數的那個方法裡面的引數就是Observer介面中的update方法中的第二個引數。
notifyObservers(number);
中的number變數引數,實際是傳遞到Observer介面中update(Observable o, Object arg)
的第二個引數arg中的。