設計模式——觀察者模式
觀察者模式
觀察者模式定義了一種一對多的依賴關係,讓多個觀察者物件同時監聽某一個主題物件。這個主題物件在狀態上發生變化時,會通知所有觀察者物件,使它們能夠自動更新自己。
觀察者模式是物件的行為模式,又叫釋出-訂閱(Publish/Subscribe)模式、模型-檢視(Model/View)模式、源-監聽器(Source/Listener)模式或從屬者(Dependents)模式。
模式結構
模式涉及角色
抽象被觀察者:持有觀察者的引用和被觀察者狀態標記,包括一些新增,刪除,通知觀察者的方法等。
抽象觀察者:有一個回撥 update 方法。
具體被觀察者:對抽象被觀察者的實現。
具體觀察者:對抽象觀察者的實現,回撥 update 方法實現。
模式結構圖
(圖片來自網路,侵刪)
示例
因為 Java 的 jdk 中已經有觀察者模式的工具類,所以以 jdk 中的觀察者模式為例。jdk 中已經定義好了被觀察者類 Observable 和觀察者介面 Observer。Observable 類中有記錄狀態屬性和持有觀察者引用的向量,然後是一些新增,刪除,通知觀察者的方法,值得注意的是只有被觀察者物件的狀態發生變化時,才會回撥觀察者的 update 方法,見方法 public void notifyObservers(Object arg)
實現程式碼。
程式碼實現
被觀察者類 Observable
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) {
/*
* a temporary array buffer, used as a snapshot of the state of
* current Observers.
*/
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);
}
protected synchronized void setChanged() {
changed = true;
}
//***其他方法就不在羅列了
觀察者介面 Observer
public interface Observer {
/**
* This method is called whenever the observed object is changed. An
* application calls an <tt>Observable</tt> object's
* <code>notifyObservers</code> method to have all the object's
* observers notified of the change.
*
* @param o the observable object.
* @param arg an argument passed to the <code>notifyObservers</code>
* method.
*/
void update(Observable o, Object arg);
}
具體被觀察者類 ConcreteObservable
/**
* 具體被觀察者
*/
class ConcreteObservable extends Observable{
public ConcreteObservable(){
super();
setChanged();
}
}
兩個具體的觀察者類 ConcreteObserver1,ConcreteObserver2
/**
* 具體觀察者
*/
class ConcreteObserver1 implements Observer{
@Override
public void update(Observable observable, Object object){
System.out.println("觀察者ConcreteObserver1 狀態: " + object.toString());
}
}
class ConcreteObserver2 implements Observer{
@Override
public void update(Observable observable, Object object){
System.out.println("觀察者ConcreteObserver2 狀態: " + object.toString());
}
}
測試程式碼
public class ObserverPattern {
public static void main(String[] args){
ConcreteObservable observable = new ConcreteObservable();
ConcreteObserver1 concreteObserver1 = new ConcreteObserver1();
ConcreteObserver2 concreteObserver2 = new ConcreteObserver2();
observable.addObserver(concreteObserver1);
observable.addObserver(concreteObserver2);
observable.notifyObservers("狀態發生變化,新狀態是 ABC");
}
}
其實看著這個程式碼很容易想起之前寫的 Java——回撥機制,其實觀察者模式也是回撥的一種實現,可以看到被觀察者類 Observable 持有觀察者引用的向量 private Vector<Observer> obs;
,當被觀察者狀態發生變化時,會通過這些已經註冊的觀察者,回撥觀察者的 void update(Observable o, Object arg);
方法。
示例 demo 見:https://github.com/lzx2011/java-scaffold
執行結果
觀察者ConcreteObserver2 狀態: 狀態發生變化,新狀態是 ABC
觀察者ConcreteObserver1 狀態: 狀態發生變化,新狀態是 ABC
應用場景
當一個物件改變時,同時需要改變其他物件,應考慮使用觀察者模式。
相關文章
- 設計模式 —— 觀察者模式設計模式
- 設計模式(觀察者模式)設計模式
- 設計模式----觀察者模式設計模式
- 【設計模式】觀察者模式設計模式
- PHP設計模式-觀察者模式PHP設計模式
- Java設計模式-觀察者模式Java設計模式
- 設計模式解析:觀察者模式設計模式
- 設計模式之觀察者模式設計模式
- 設計模式之-觀察者模式設計模式
- 設計模式 #6 (觀察者模式)設計模式
- JS設計模式(觀察者模式)JS設計模式
- 設計模式(十六)觀察者模式設計模式
- 設計模式之【觀察者模式】設計模式
- 設計模式(9) 觀察者模式設計模式
- 設計模式-觀察者模式上設計模式
- 設計模式-觀察者模式下設計模式
- Go 設計模式之觀察者模式Go設計模式
- 設計模式之觀察者模式(一)設計模式
- PHP 設計模式之——觀察者模式PHP設計模式
- 設計模式實戰 - 觀察者模式設計模式
- PHP設計模式(5)—— 觀察者模式PHP設計模式
- JavaScript設計模式之觀察者模式JavaScript設計模式
- golang設計模式之觀察者模式Golang設計模式
- Java 設計模式之《觀察者模式》Java設計模式
- 設計模式解析-1:觀察者模式設計模式
- python設計模式之觀察者模式Python設計模式
- PHP設計模式之觀察者模式PHP設計模式
- 《Head First 設計模式》:觀察者模式設計模式
- PHP 設計模式之觀察者模式PHP設計模式
- 簡說設計模式——觀察者模式設計模式
- 極簡設計模式-觀察者模式設計模式
- 徒手擼設計模式-觀察者模式設計模式
- 設計模式中的觀察者模式設計模式
- GoLang設計模式13 - 觀察者模式Golang設計模式
- 設計模式(Swift) - 3.觀察者模式、建造者模式設計模式Swift
- 設計模式(python實現):觀察者模式設計模式Python
- C#設計模式(17)——觀察者模式C#設計模式
- Android 中的設計模式:觀察者模式Android設計模式