?? 今天有同事問我關于Observer模式的一個問題,說觀察者(Observer)為什么要依賴于主題(Subject),如下圖所示:
?
??? 從上圖可以看出,具體的觀察者對具體的主題有一個依賴, 而且從JDK本身提供的Observer接口,我們也可以看到,確實對主題(在JDK的實現(xiàn)中,為Observable接口)有一個依賴,如代碼所示:
?
public interface Observer {
void update(Observable o, Object arg);
}
??
?
?? 這個是為什么呢,為什么這里會依賴主題對象?其實這個跟Subject與Observer之間通訊的方式有關,當Subject本身狀態(tài)發(fā)生變化時,會去通知注冊了的Observer(即調用每個observer的update()方法),那么這個時候,主題本身要怎么樣去給Observer傳輸其需要的數據呢?
??
?? 在我們看到的大多數觀察者的實現(xiàn)中,主題(Subject)在通知注冊的Observer時,都會把Observer所需要的數據封裝好,傳給Observer,這個也就是所謂的‘推’的模式,主題主動將數據推給觀察者,這種情況下,Observer的接口往往定義如下:
??????
public interface Observer {
void update(Object arg);//從主題傳入的數據
}
?
?? 在這種‘推’的模式下,觀察者本身是不依賴于主題對象的。 但還有另外一種所謂‘拉’的通訊方式,是指觀察者在需要數據的時候主動從主題對象中獲取,這個情況下面就會出現(xiàn)觀察者依賴于主題對象,
???
public interface Observer {
void update(Subject subject);
}
?
??? 由于這種拉的實現(xiàn)方法出現(xiàn)的比較少,而且‘拉’數據的模式有一個比較大的缺點,那就是出現(xiàn)了主題對象和觀察者對象之間的循環(huán)依賴,處理不好則很容易出來死循環(huán)。
???
???? 但是對于一個完整的觀察者模式來說,這兩種數據傳輸的方式都是需要的,這也就是JDK的Observer接口中的update()方法要有兩個參數的原因(Obervable對象一般對應于拉模式,Object對象一般對應于推模式),如果你做過Swing編程,你會發(fā)現(xiàn)在Swing的事件處理中,listner(實際上就是Observer)所接受的參數也支持推拉兩種數據方式,如
?????
public interface MouseListener extends EventListener {
public void mouseClicked(MouseEvent e);
。。。其他略
}
??? 這里的MouseEvent對象實際上也包含了數據來源對象(觸發(fā)事件的對象),即具體主題對象,而除了主題對象之外的其他屬性,我們都可以看成是推模式中所傳的數據。
?
???? 好了,解決了同事了疑問,還需要點明Observer模式的另一職責。由于我們大多數的Observer模式的實現(xiàn)都很簡單,在這樣的實現(xiàn)下,主題對象大多只擁有一個職責,那就是管理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中獲得
//真正的業(yè)務邏輯
public void run()
{
//從遠程獲得messages
//通知觀察者
}
?
??? 完成一個完整的Observer模式很難,考慮的東西比較多(光是通知Observer這部分就有幾種不同的實現(xiàn)方式),不推薦每次都需要實現(xiàn)一個很完整的Observer模式,但是我們不應該遺忘這些構成完整Observer模式鎖需要的部分。
?
?
?
更多文章、技術交流、商務合作、聯(lián)系博主
微信掃碼或搜索:z360901061
微信掃一掃加我為好友
QQ號聯(lián)系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元

