使用觀察者(Observer)實現對象監聽
Bromon原創 請尊重版權
有非常多的時候,我們希望自己的程序能夠監視數據的變化,然后做出響應,這種情況非常多,比如探測數據庫中數據的變化、檢測用戶狀態的變化等等。通常我們都缺乏一種雙工通信的機制,只能選擇讓程序做論詢,隔一段時間檢測一次數據變化,記錄下來與上一次檢測結果做對比,從而判斷數據是否發生了變化。毫無疑問這樣的方式很笨拙,不僅寫起來痛苦,跑起來也耗資源,是典型的用80%的時間解決20%的問題。
觀察者(Observer)是一種模式,也是Java中的一個API,它讓一個值對象(Value Object)具備自省的功能,當他發現自己的狀態改變了,就向相關的對象發送消息,這樣的監聽方式當然比輪詢好。我感冒了自己會去醫院,用不著醫生每個月來問一次。禽獸·宇楓曾經給了我一段麻將游戲的服務器端代碼,本來是讓我研究一下麻將的算法,但是卻被其中Observer的使用所吸引,這樣寫出來的服務器執行效率很高。我曾經用線程池+反射+觀察者寫了一個即時消息的服務器,既有socket的方便也具備udp的高效,可惜后來因為大幅修改設計代碼作廢了,不過觀察者還是值得研究。
Java的Observer API是對觀察者模式的一個實現。假設我們有一個對象容器,其中存放用戶消息,我希望這個容器自省,當有新的消息進來就自動觸發觀察者作出響應。首先定義消息對象,是個很簡單的值對象:
然后寫一個存放Message的容器,容器使用ArrayList來存放對象是個很好的選擇,也很簡單:
這個類繼承了Observable類,并且對其中的add方法做了手腳,很明顯,add方法的作用是向ArrayList容器中放入一個對象,這正是我們想監聽的操作,所以有了:
uper.setChanged();
super.notifyObservers(m);
這意思是一旦調用add方法,這個類自己就會向所有注冊過的觀察者發送消息,消息內容是什么呢?內容就是m,是存放消息的容器,觀察者可以收到這個改變了狀態的容器,然后對它進行操作,從而實現了對容器的監聽,當然,我們只實現了對add方法的監聽,你也可以試試其他的。
需要特別注意的是這是一個不完整的單例類,寫成單例是為了要保證整個jvm中只有這一個存放消息的容器,而不寫成完整的單例,原因是將來可能要提供另外的實例化方法。所以理解起來可能稍微難一點,大家可以參考一下設計模式中的單例模式。
下面就是編寫觀察者并且注冊它:
這個類繼承Oberver接口,update(Observable,Object)是必須提供的方法,在這個方法中我們接收被觀察類傳過來的數據(含有消息的容器),然后取出其中最后一個,讀取它的內容。
Java里的觀察者使用起來是非常簡單的。我們的例子好處是所有的操作都在內存中進行,而且不需要輪詢,效率非常高,缺點是一旦當機內存中的數據就丟失了,所以如果有一套比較完善的對象緩沖機制,就可以應付復雜的應用,寫出高效簡潔的多線程服務器。