以下內容都是從其他文章裏摘抄的。
/**
* 觀察者模式應用場景實例
*
* 免責聲明:本文只是以哈票網舉例,示例中並未涉及哈票網任何業務代碼,全部原創,如有雷同,純屬巧合。
*
* 場景描述:
* 哈票以購票爲核心業務(此模式不限於該業務),但圍繞購票會產生不同的其他邏輯,如:
* 1、購票後記錄文本日誌
* 2、購票後記錄數據庫日誌
* 3、購票後發送短信
* 4、購票送抵扣卷、兌換卷、積分
* 5、其他各類活動等
*
* 傳統解決方案:
* 在購票邏輯等類內部增加相關代碼,完成各種邏輯。
*
* 存在問題:
* 1、一旦某個業務邏輯發生改變,如購票業務中增加其他業務邏輯,需要修改購票核心文件、甚至購票流程。
* 2、日積月累後,文件冗長,導致後續維護困難。
*
* 存在問題原因主要是程序的"緊密耦合",使用觀察模式將目前的業務邏輯優化成"鬆耦合",達到易維護、易修改的目的,
* 同時也符合面向接口編程的思想。
*
* 觀察者模式典型實現方式:
* 1、定義2個接口:觀察者(通知)接口、被觀察者(主題)接口
* 2、定義2個類,觀察者對象實現觀察者接口、主題類實現被觀者接口
* 3、主題類註冊自己需要通知的觀察者
* 4、主題類某個業務邏輯發生時通知觀察者對象,每個觀察者執行自己的業務邏輯。
*
* 示例:如以下代碼
*
*/
觀察者模式的效果有以下的優點:
第一、觀察者模式在被觀察者和觀察者之間建立一個抽象的耦合。被觀察者角色所知道的只是一個具體觀察者列表,每一個具體觀察者都符合一個抽象觀察者的接口。被觀察者並不認識任何一個具體觀察者,它只知道它們都有一個共同的接口。
由於被觀察者和觀察者沒有緊密地耦合在一起,因此它們可以屬於不同的抽象化層次。如果被觀察者和觀察者都被扔到一起,那麼這個對象必然跨越抽象化和具體化層次。
第二、觀察者模式支持廣播通訊。被觀察者會向所有的登記過的觀察者發出通知,
觀察者模式有下面的缺點:
第一、如果一個被觀察者對象有很多的直接和間接的觀察者的話,將所有的觀察者都通知到會花費很多時間。
第二、如果在被觀察者之間有循環依賴的話,被觀察者會觸發它們之間進行循環調用,導致系統崩潰。在使用觀察者模式是要特別注意這一點。
第三、如果對觀察者的通知是通過另外的線程進行異步投遞的話,系統必須保證投遞是以自恰的方式進行的。
第四、雖然觀察者模式可以隨時使觀察者知道所觀察的對象發生了變化,但是觀察者模式沒有相應的機制使觀察者知道所觀察的對象是怎麼發生變化的。
觀察者模式的應用場景:
1、 對一個對象狀態的更新,需要其他對象同步更新,而且其他對象的數量動態可變。
2、 對象僅需要將自己的更新通知給其他對象而不需要知道其他對象的細節。
Observer 模式應該可以說是應用最多、影響最廣的模式之一,因爲 Observer 的一個實例 Model/View/Control( MVC) 結構在系統開發架構設計中有着很重要的地位和意義, MVC實現了業務邏輯和表示層的解耦。在 MFC 中, Doc/View(文檔視圖結構)提供了實現 MVC 的框架結構。在 Java 陣容中, Struts 則提供和 MFC 中 Doc/View 結構類似的實現 MVC 的框架。另外 Java 語言本身就提供了 Observer 模式的實現接口。當然, MVC 只是 Observer 模式的一個實例。 Observer 模式要解決的問題爲: 建立一個一( Subject)對多( Observer) 的依賴關係, 並且做到當“一” 變化的時候, 依賴這個“一”的多也能夠同步改變。
在GOF的《設計模式:可複用面向對象軟件的基礎》一書中對觀察者模式是這樣說的:定義對象間的一種一對多的依賴關係,當一個對象的狀態發生改變時,所有依賴於它的對象都得到通知並被自動更新。當一個對象發生了變化,關注它的對象就會得到通知;這種交互也稱爲發佈-訂閱(publish-subscribe)。目標是通知的發佈者,它發出通知時並不需要知道誰是它的觀察者。
最常見的一個例子就是: 對同一組數據進行統計分析時候, 我們希望能夠提供多種形式的表示 (例如以表格進行統計顯示、柱狀圖統計顯示、百分比統計顯示等)。這些表示都依賴於同一組數據, 我們當然需要當數據改變的時候, 所有的統計的顯示都能夠同時改變。 Observer 模式就是解決了這一個問題。
UML類圖:
Subject(目標)
——目標知道它的觀察者。可以有任意多個觀察者觀察同一個目標;
——提供註冊和刪除觀察者對象的接口。
Observer(觀察者)
——爲那些在目標發生改變時需獲得通知的對象定義一個更新接口。
ConcreteSubject(具體目標)
——將有關狀態存入各ConcreteObserver對象;
——當它的狀態發生改變時,向它的各個觀察者發出通知。
ConcreteObserver(具體觀察者)
——維護一個指向ConcreteSubject對象的引用;
——存儲有關狀態,這些狀態應與目標的狀態保持一致;
——實現Observer的更新接口以使自身狀態與目標的狀態保持一致。
觀察者模式按照以下方式進行協作:
- 當ConcreteSubject發生任何可能導致其觀察者與其本身狀態不一致的改變時,它將通知它的各個觀察者;
- 在得到一個具體目標的改變通知後,ConcreteObserver對象可向目標對象查詢信息。ConcreteObserver使用這些信息以使它的狀態與目標對象的狀態一致。
以下是調用時序圖:
適用場合
在以下任一情況下都可以使用觀察者模式:
- 當一個抽象模型有兩個方面,其中一個方面依賴於另一方面。將這二者封裝在獨立的對象中以使它們可以各自獨立的改變和複用;
- 當對一個對象的改變需要同時改變其它對象,而不知道具體有多少對象有待改變;
- 當一個對象必須通知其它對象,而它又不能假定其它對象是誰;也就是說,你不希望這些對象是緊密耦合的。
代碼實現:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
|
#include
<iostream> #include
<list> using namespace std; class Observer { public : virtual void Update( int )
= 0; }; class Subject { public : virtual void Attach(Observer
*) = 0; virtual void Detach(Observer
*) = 0; virtual void Notify()
= 0; }; class ConcreteObserver
: public Observer { public : ConcreteObserver(Subject
*pSubject) : m_pSubject(pSubject){} void Update( int value) { cout
<< "ConcreteObserver
get the update. New State:" <<
value << endl; } private : Subject
*m_pSubject; }; class ConcreteObserver2
: public Observer { public : ConcreteObserver2(Subject
*pSubject) : m_pSubject(pSubject){} void Update( int value) { cout
<< "ConcreteObserver2
get the update. New State:" <<
value << endl; } private : Subject
*m_pSubject; }; class ConcreteSubject
: public Subject { public : void Attach(Observer
*pObserver); void Detach(Observer
*pObserver); void Notify(); void SetState( int state) { m_iState
= state; } private : std::list<Observer
*> m_ObserverList; int m_iState; }; void ConcreteSubject::Attach(Observer
*pObserver) { m_ObserverList.push_back(pObserver); } void ConcreteSubject::Detach(Observer
*pObserver) { m_ObserverList. remove (pObserver); } void ConcreteSubject::Notify() { std::list<Observer
*>::iterator it = m_ObserverList.begin(); while (it
!= m_ObserverList.end()) { (*it)->Update(m_iState); ++it; } } int main() { //
Create Subject ConcreteSubject
*pSubject = new ConcreteSubject(); //
Create Observer Observer
*pObserver = new ConcreteObserver(pSubject); Observer
*pObserver2 = new ConcreteObserver2(pSubject); //
Change the state pSubject->SetState(2); //
Register the observer pSubject->Attach(pObserver); pSubject->Attach(pObserver2); pSubject->Notify(); //
Unregister the observer pSubject->Detach(pObserver); pSubject->SetState(3); pSubject->Notify(); delete pObserver; delete pObserver2; delete pSubject; } |
vs2013運行結果:
示例2代碼實現:
這裏的目標 Subject 提供依賴於它的觀察者 Observer 的註冊( Attach) 和註銷( Detach)操作,並且提供了使得依賴於它的所有觀察者同步的操作( Notify)。 觀察者 Observer 則提供一個 Update 操作, 注意這裏的 Observer 的 Update 操作並不在 Observer 改變了 Subject 目標狀態的時候就對自己進行更新, 這個更新操作要延遲到 Subject 對象發出 Notify 通知所有Observer 進行修改(調用 Update)。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
|
#include
<iostream> #include
<string> #include
<list> using namespace std; class Subject; //抽象觀察者 class Observer { protected : string
name; Subject
*sub; public : Observer(string
name, Subject *sub) { this ->name
= name; this ->sub
= sub; } virtual void update()
= 0; }; //具體的觀察者,看股票的 class StockObserver
: public Observer { public : StockObserver(string
name, Subject *sub) :Observer(name, sub) { } void update(); }; //具體的觀察者,看NBA的 class NBAObserver
: public Observer { public : NBAObserver(string
name, Subject *sub) :Observer(name, sub) { } void update(); }; //抽象通知者 class Subject { protected : list<Observer*>
observers; public : string
action; virtual void attach(Observer*)
= 0; virtual void detach(Observer*)
= 0; virtual void notify()
= 0; }; //具體通知者,祕書 class Secretary
: public Subject { void attach(Observer
*observer) { observers.push_back(observer); } void detach(Observer
*observer) { list<Observer
*>::iterator iter = observers.begin(); while (iter
!= observers.end()) { if ((*iter)
== observer) { observers.erase(iter); } ++iter; } } void notify() { list<Observer
*>::iterator iter = observers.begin(); while (iter
!= observers.end()) { (*iter)->update(); ++iter; } } }; void StockObserver::update() { cout
<< name << "
收到消息:" <<
sub->action << endl; if (sub->action
== "樑所長來了!" ) { cout
<< "我馬上關閉股票,裝做很認真工作的樣子!" <<
endl; } } void NBAObserver::update() { cout
<< name << "
收到消息:" <<
sub->action << endl; if (sub->action
== "樑所長來了!" ) { cout
<< "我馬上關閉NBA,裝做很認真工作的樣子!" <<
endl; } } int main() { Subject
*dwq = new Secretary(); //創建觀察者<br> //被觀察的對象 Observer
*xs = new NBAObserver( "xiaoshuai" ,
dwq); Observer
*zy = new NBAObserver( "zouyue" ,
dwq); Observer
*lm = new StockObserver( "limin" ,
dwq); //加入觀察隊列 dwq->attach(xs); dwq->attach(zy); dwq->attach(lm); //事件 dwq->action
= "去吃飯了!" ;<br> //通知 dwq->notify(); cout
<< endl; dwq->action
= "樑所長來了!" ; dwq->notify(); return 0; } |
運行結果: