?? 今天有同事問我關于Observer模式的一個問題,說觀察者(Observer)為什么要依賴于主題(Subject),如下圖所示:
?
??? 從上圖可以看出,具體的觀察者對具體的主題有一個依賴, 而且從JDK本身提供的Observer接口,我們也可以看到,確實對主題(在JDK的實現中,為Observable接口)有一個依賴,如代碼所示:
?
public interface Observer { void update(Observable o, Object arg); }
??
?
?? 這個是為什么呢,為什么這里會依賴主題對象?其實這個跟Subject與Observer之間通訊的方式有關,當Subject本身狀態發生變化時,會去通知注冊了的Observer(即調用每個observer的update()方法),那么這個時候,主題本身要怎么樣去給Observer傳輸其需要的數據呢?
??
?? 在我們看到的大多數觀察者的實現中,主題(Subject)在通知注冊的Observer時,都會把Observer所需要的數據封裝好,傳給Observer,這個也就是所謂的‘推’的模式,主題主動將數據推給觀察者,這種情況下,Observer的接口往往定義如下:
??????
public interface Observer { void update(Object arg);//從主題傳入的數據 }
?
?? 在這種‘推’的模式下,觀察者本身是不依賴于主題對象的。 但還有另外一種所謂‘拉’的通訊方式,是指觀察者在需要數據的時候主動從主題對象中獲取,這個情況下面就會出現觀察者依賴于主題對象,
???
public interface Observer { void update(Subject subject); }
?
??? 由于這種拉的實現方法出現的比較少,而且‘拉’數據的模式有一個比較大的缺點,那就是出現了主題對象和觀察者對象之間的循環依賴,處理不好則很容易出來死循環。
???
???? 但是對于一個完整的觀察者模式來說,這兩種數據傳輸的方式都是需要的,這也就是JDK的Observer接口中的update()方法要有兩個參數的原因(Obervable對象一般對應于拉模式,Object對象一般對應于推模式),如果你做過Swing編程,你會發現在Swing的事件處理中,listner(實際上就是Observer)所接受的參數也支持推拉兩種數據方式,如
?????
public interface MouseListener extends EventListener { public void mouseClicked(MouseEvent e); 。。。其他略 }
??? 這里的MouseEvent對象實際上也包含了數據來源對象(觸發事件的對象),即具體主題對象,而除了主題對象之外的其他屬性,我們都可以看成是推模式中所傳的數據。
?
???? 好了,解決了同事了疑問,還需要點明Observer模式的另一職責。由于我們大多數的Observer模式的實現都很簡單,在這樣的實現下,主題對象大多只擁有一個職責,那就是管理Observer的職責(包括通知Observer),
????
class ConcreteSubject implement ISubject { private List observers=.. public void addObserver(Observer obs) { //add observer } public void removeObserver(Observer obs) { //remove observer } public void notifyObservers(Object obj) { //notify observers } }
?
??? 加上Observer模式是為了解決一對多的關系,久而久之,導致大多數人都忘記了主題對象(Subject)本身還應該有另一個職責,管理Observer只是主題(Subject)對象應有的共同的職責,不要忘了,還有多主題對象這么一回事。舉個以前看到的例子,
??? 假設我們的主題對象需要從遠程獲取一些數據,并分別的將其記錄在DB中,和顯示在Screen上,那么套用Observer模式,可以表示為:
????
?
?? 其中,DBObserver將拿到的數據寫到DB中,而DisplayObserver將拿到的數據顯示在SCREEN上,而MessagesSubject則有了兩個職責,一個是我們前面說的管理Observer的職責,另一個是去遠程取數據的職責,而這個我認為才是主題對象(Subject)應該有的具體的職責。
??
public class MessagesSubject extends AbstractSubject implements Runnable { //管理Observer的職責會從AbstractSuject中獲得 //真正的業務邏輯 public void run() { //從遠程獲得messages //通知觀察者 }
?
??? 完成一個完整的Observer模式很難,考慮的東西比較多(光是通知Observer這部分就有幾種不同的實現方式),不推薦每次都需要實現一個很完整的Observer模式,但是我們不應該遺忘這些構成完整Observer模式鎖需要的部分。
?
?
?
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
