Observer Pattern,中文叫觀察者模式, 或者有人稱發布/訂閱模式, 用於單一物件對多個物件的情形下, 當此單一物件狀態改變時, 其他多個物件可以取得通知並做更新的動作.
.Thinking in Observer Pattern
定義
- Observer Pattern 為物件之間定義一對多的關係,當一個物件的狀態改變,其關係物件都會收到通知,並自動更新。
在架構上, Observer包含主題物件以及觀察者, 兩者呈一對多的關係, 觀察者訂閱感興趣的主題, 一個主題由一到多個觀察者訂閱, 當主題物件(發行者)有狀態變化時, 會主動通知各個觀察者(訂閱者), 由觀察者去做更新的動作取得最新狀態, 並依各自需求去做相對應的處理.
在需求使用上, Observer算是很常見的模型, 只要是一對多的架構就很常見到這個模型, 像是GUI架構的event處理就是一個很明顯的例子, 以下簡單舉個例子, 另外注意一點, 舉例並不代表一定要用這個模型去做處理, 也有其他模型可以達到相同的目的, 在設計時要以自己的需求跟狀況去做考量活用.
- 建立很多視窗按鈕, 每個都註冊滑鼠訊息, 此時滑鼠的訊息處理器就是一個主題物件, 當滑鼠有狀態更新時, 就會通知每個有註冊的視窗按鈕, 當視窗按鈕收到消息, 前往取得滑鼠最新狀態後, 就可以依照各自的需求去做處理.
.implement
Observer的主要原件有兩個, 實作上並不複雜, 只要把主題以及觀察者的角色定義弄清楚就可以, 以下列出幾個要點並做說明.
- 定義出觀察者(以下稱Observer)的interface.
- 定義出主題(以下稱subject)的interface.
- 實做subject.
- 實做Observer.
.1.定義Observer的interface
Observer功能沒有什麼特別之處, 定義固定的update功能即可.
- Update - 給subject在狀態改變時呼叫, 一旦被呼叫就去取得subject最新狀態來做相對應處理.
IObserver
class IObserver { public: virtual void Update()=0; };
.2.定義subject的interface
網路上有些文章並沒有處理subject的interface, 而在此處為什麼要做subject的interface, 主要原因是subject主要功能包含了兩個部分, 其中狀態是屬於變動部分, 依各種需求在撰寫上也會不一樣, 而subject本身的註冊等基本功能是屬於不變動的功能, 所以理所當然把變動與不變動部分切分出來, 增加架構的彈性.
雖說要把兩個部分切分出來, 但要分出哪個部分才是適當的, 合理的做法是把註冊等功能都非變動部分切分出來, 而變動的狀態部分依各種的需求實做, 日後有需要可較彈性的實作別種狀態的subject, 另外更進一步看, 非變動的註冊等功能, 程式碼很固定不會改變, 以abstract處理, 或者有其他考量下用interface然後再多一層, 端看個人怎麼設計都可以, 在這邊我以abstract class來處理.
- ObserverCollection - 儲存已註冊的IObserver.
- RegisterObserver - 註冊IObserver.
- UnRegisterObserver - 註銷IObserver.
- NotifyAllObservers - 當本身得知狀態改變時呼叫, 裡面呼叫所有IObserver的Update函式通知該取已更新的狀態了.
ISubject
class ISubject { public: ISubject(){} ~ISubject(){} void RegisterObserver(IObserver *observer) { //add observer } void UnRegisterObserver(IObserver *observer) { //remove observer } NotifyAllObservers() { //Call All Update in Observer... //這邊可以先確認每一個observer是有效的在執行, //防範observer已經釋放卻沒有UnRegisterObserver //m_ObserverCollection[].Update(); } public: //IObserver collection m_ObserverCollection; };
.3.實做subject
實作Subject主要就是加上自訂的狀態, 取狀態以及設定狀態都處理好, 另外不要忘了繼承(或實作)ISubject.
Subject
class Subject:public ISubject { public: Subject(){ m_state = INIT_STATE;} ~Subject(){} MyState GetState() { return m_state; } void SetState(Mystate state) { m_state = state; } public: MyState m_state; };
.4.實做Observer
Observer本身注意要重載Update函式, 以及記錄自己註冊了哪個Subject, 用於Update時可以呼叫來取狀態.
Observer
class Observer : public IObserver { public: Observer(){} ~Observer(){} virtual void Update() { //get state MyState state = m_subject.GetState(); //state processing.... } public: Subject m_subject; };
.Observer完整架構及執行
Observer
void main() { Subject sub; Observer ob1,ob2; sub.RegisterObserver(&ob1); sub.RegisterObserver(&ob2); //...... //途中Subject有更新時 sub.SetState(STATE_ORZ); sub.NotifyAllObservers(); //...... sub.UnRegisterObserver(&ob1); sub.UnRegisterObserver(&ob2); }
沒有留言:
張貼留言