觀察者模式在工程專案裡具有非常廣泛的應用,本文聊一聊自己對觀察者模式的一些理解和實現。
按照我自己的風格,我非常不贊同講各種原理看起來深入淺出頭頭是道最後就貼幾句偽**甚至偽**都沒有就完事的部落格方式。既然寫在部落格上了,就是為了供他人討論和借鑑。簡而言之,上**,講道理。
#include
#include
using
namespace
std;
#include
#include
class subject;
class iobserver
;class subject
void detach(iobserver *obs)
}void trigger()
}private:
boost::mutex m_mutex;
list
m_ptrobservers;
};class observer : public iobserver
};int main()
subject.trigger();
return
0;}
當然這其中的問題是多方面的,顯然,在trigger裡面,(*it)->ontrigger(this),如果觀察者在自己的實現中做了detach或者atach其他指標的操作,那麼死鎖是不可避免的了。因此最好使用遞迴鎖:
boost::recursive_mutex m_mutex;
上鎖時:
boost::recursive_mutex::scoped_lock lock(m_mutex);
這樣是不是問題就解決了呢?顯然問題仍然非常嚴重:由於detach或者atach操作修改了容器內的結構,因此在
for (listiter it = m_ptrobservers.begin(); it != m_ptrobservers.end(); ++it)
這段**時,迭代器失效會直接導致程式的崩潰。
如何解決這樣的問題,這裡就需要一些技巧了。
#include
#include
using
namespace
std;
#include
#include
class subject;
class iobserver
;class subject
void atatch(iobserver *obs)
else
--m_nusecount;
}void detach(iobserver *obs)
--m_nusecount;
}void trigger()
m_ptrtoadd.clear();
}for (listiter it = m_ptrobservers.begin(); it != m_ptrobservers.end(); )
else}}
--m_nusecount;
}private:
boost::recursive_mutex m_mutex;
list
m_ptrobservers;
list
m_ptrtoadd;
int m_nusecount;
};class observer : public iobserver
};int main()
subject.trigger();
return
0;}
這一次,我們使用了乙個usercount作標記,用來標誌當前有幾處正在訪問觀察者列表,如果發現其他處在訪問,那麼盡量避免直接add或者erase一類會使迭代器失效的操作,等到有機會以遍歷觀察者列表並且只有當前處在訪問該列表時,再做真正的增加或刪除操作。
另外,還有更加精妙的方案來可以解決我們繁瑣的使用usercount自己進行++,–操作,那就是通過智慧型指標的機制實現copy_on_write-ref_on_read,打算再開一篇博文貼**講原理。
觀察者模式實現
公升級觀察者 var observer function 定義介面 return else trigger方法用於觸發觀察者物件中的事件 type 要觸發的事件名稱 trigger用於觸發觀察者物件中的事件 trigger function type,val off方法用於移除某個事件 off fu...
PHP實現觀察者模式
特點 觀察者模式定義物件的一對多依賴,這樣一來,當乙個物件改變狀態時,它的所有依賴者都會收到通知並自動更新 觀察者模式利用 組合 將許多觀察者組合進主題中。物件 觀察者 主題 之間的這種關係不是通過繼承產生的,而是在執行時利用組合的方式產生的。多用組合,少用繼承!觀察者模式的優點和缺點 觀察者模式的...
C 實現觀察者模式
定義物件間的一種一對多的依賴關係,當乙個物件的狀態發生改變時,所有依賴於它的物件都得到通知並被自動更新。完美的將觀察者和被觀察的物件分離開。有時又被稱為 模型 檢視 view 模式 源 收聽者 listener 模式 或為發布 訂閱模式 目標就是通知的發布者,觀察者是通知的訂閱者 接受通知 obse...