談談java中的觀察者模式

圖片.png
前言
瞭解設計模式的童鞋應該都知道觀察者模式,類似於上圖的結構,其中Observer作為觀察者,Observable則作為被觀察者,Observable的狀態改變會給註冊的Observer進行通知,考慮易用和低耦合,保證高度的協作。
Demo展示
我們首先來看一下demo,也就是上圖類圖中所展示的程式,MyObservable非常簡單,只是繼承了Observable:
public class MyObservable extends Observable{ public static void main(String[] args) { MyObservable myObservable = new MyObservable(); myObservable.addObserver(new MyObserver()); myObservable.setChanged(); myObservable.notifyObservers("aaa"); } }
此處為了簡化結構,直接將main方法寫在MyObservable中用於進行效果的測試,main中我們先例項化了MyObservable類,並且將一個MyObserver例項用addObserver方法加入它的觀察者列表中,然後通過setChanged改變changed的狀態值,隨後便可以notifyObservers,裡面可以帶引數做訊息傳遞,也可以不帶引數。關於changed,是因為只有該變數為true的情況下,才會進行通知,否則notifyObservers是無法通知到具體Observer的。
MyObserver的結構也非常簡單,由於繼承了Observer介面,因此需要實現它的抽象方法update,這個方法也是用於接收Observable發來的通知並執行相應的處理邏輯的:
public class MyObserver implements Observer{ public void update(Observable o, Object arg) { System.out.println("觀察物件為:" + o + ";傳遞引數為:" + arg); } }
執行一下demo,可以看到結果為:
觀察物件為:com.sunny.MyObservable@60e53b93;傳遞引數為:aaa
而在註釋了setChanged方法之後,會發現沒有任何輸出,可以理解為,並沒有真正通知到Observer。
原理解析
原理非常簡單,檢視Observable原始碼即可。其實從類圖中就可以看出一些端倪,Observable中只有兩個變數,一個是changed,一個是obs,從之前的分析可以看出changed只是一個狀態指示的變數,那麼obs應該就是一個用於儲存Observer例項的變量了,它具體是用一個Vector來進行儲存的。
private boolean changed = false; private Vector<Observer> obs;
這樣的情況下,我們很容易就可以猜測,obs的初始化應該是在Observable的構造方法中實現的,果不其然,構造方法也僅僅只是完成了obs的初始化:
public Observable() { obs = new Vector<>(); }
然後我們更為關心的是Observable與Observer之間的關係,那麼就是重點關注兩個方法,addObserver和notifyObservers。addObserver很顯然,裡面的主要操作是將作為引數傳入的Observer加入到Vector中:
public synchronized void addObserver(Observer o) { if (o == null) throw new NullPointerException(); if (!obs.contains(o)) { obs.addElement(o); } }
notifyObservers則是逐一通知Observer的過程,不過在這個方法中會檢查changed的值,以及會在通知完成後對changed歸零(其中clearChanged方法就是將changed變數重新置為false):
public void notifyObservers(Object arg) { Object[] arrLocal; synchronized (this) { if (!changed) return; arrLocal = obs.toArray(); clearChanged(); } for (int i = arrLocal.length-1; i>=0; i--) ((Observer)arrLocal[i]).update(this, arg); }
到這裡基本上整個基於jdk實現的觀察者模式的原理已經非常明瞭了,另外值得注意的一個點是,這個實現中用了一些措施來使它執行緒安全。比如,使用執行緒安全的容器Vector,addObserver方法進行了枷鎖,在notifyObservers方法中,有一個操作進行了加鎖:
synchronized (this) { if (!changed) return; arrLocal = obs.toArray(); clearChanged(); }
這裡主要確保了對changed變數的驗證和清零操作以及將obs中的元素賦值給arrLocal的過程是原子操作,這裡減少了鎖的粒度,提高併發性,也因此大家能明白為何需要arrLocal這個變量了,隨後對arrLocal陣列進行便利並逐一通知則不需要加鎖了,因為arrLocal已經是一個本地變數,並未暴露。
綜上,就是基於jdk實現觀察者模式的主要原理了。
歡迎小夥伴與我討論哦~
郵箱: ofollow,noindex">[email protected]
本文歡迎轉載,請註明本文地址: https://www.jianshu.com/p/e45a12e3ac60