觀(guān)察者模式是設計模式中行為模型的一種,是定義對象間的一種一對多的依賴(lài)關(guān)系,以便當一個(gè)對象的狀態(tài)發(fā)生改變時(shí),所有依賴(lài)于它的對象都得到通知并自動(dòng)刷新。
典型的應用情形為:
夜里有一只貓大叫了一聲,同處一屋的老鼠接受到了貓大叫的信息,于是開(kāi)始逃跑。同樣,主人聽(tīng)到了,被吵醒了;小孩子聽(tīng)到了,被嚇哭了。
實(shí)現代碼如下:

1using System;
2
3namespace DelegateEvent
4
5{
6
7 /// <summary>
8
9 /// Subject 的摘要說(shuō)明。
10
11 /// 被觀(guān)察者抽象基類(lèi)
12
13 /// 所有被觀(guān)察者對象都繼承此類(lèi)
14
15 /// 做為抽象基類(lèi),此類(lèi)不允許直接進(jìn)行實(shí)例化
16
17 /// 此類(lèi)中首先定義委托
18
19 /// 再有委托定義事件
20
21 /// 然后創(chuàng )立與委托想關(guān)聯(lián)的方法Notify
22
23 /// </summary>
24
25 public abstract class Subject
26
27 {
28
29 public Subject()
30
31 {
32
33 //
34
35 // TODO: 在此處添加構造函數邏輯
36
37 //
38
39 }
40
41 /// <summary>
42
43 /// 創(chuàng )建一個(gè)委托
44
45 /// </summary>
46
47 public delegate void SubEventHandler();
48
49 /// <summary>
50
51 /// 根據SubEventHandler創(chuàng )建一個(gè)事件
52
53 /// </summary>
54
55 public event SubEventHandler SubEvent;
56
57 /// <summary>
58
59 /// 將于委托相連接的方法
60
61 /// </summary>
62
63 protected void Notify()
64
65 {
66
67 if(this.SubEvent!=null)
68
69 this.SubEvent();
70
71 }
72
73 }
74
75}
76
77//------------------------------------------------------------------------------------------
78
79被觀(guān)察者基類(lèi)完成后我們再來(lái)創(chuàng )建觀(guān)察者基類(lèi)Observer.
80
81namespace DelegateEvent
82
83{
84
85 /// <summary>
86
87 /// Observer 的摘要說(shuō)明。
88
89 /// 觀(guān)察者抽象基類(lèi)
90
91 /// 所有觀(guān)察者對象都由此類(lèi)派生
92
93 /// 使用此類(lèi)進(jìn)行對事件的注冊
94
95 /// 并和事件的方法關(guān)聯(lián)
96
97 /// 另外定義了一個(gè)抽象方法Response
98
99 /// 可以由子類(lèi)來(lái)進(jìn)行覆蓋
100
101 /// </summary>
102
103 public abstract class Observer
104
105 {
106
107 public Observer(Subject childModel)
108
109 {
110
111 //注冊SubEvent事件通過(guò)SubEventHandler委托和Response方法關(guān)聯(lián)
112
113 //子類(lèi)通過(guò)調用此構造函數完成事件的注冊
114
115 childModel.SubEvent+=new Subject.SubEventHandler(Response);
116
117 }
118
119
120
121 /// <summary>
122
123 /// 抽象方法,用于引發(fā)事件
124
125 /// </summary>
126
127 public abstract void Response();
128
129 }
130
131}
132
133同理,我們還可以繼續創(chuàng )建另一個(gè)觀(guān)察者基類(lèi),用來(lái)響應不同的事件的方法。
134
135namespace DelegateEvent
136
137{
138
139 /// <summary>
140
141 /// Observer2 的摘要說(shuō)明。
142
143 /// 注冊了兩個(gè)事件的方法。
144
145 /// </summary>
146
147 public abstract class Observer2
148
149 {
150
151 public Observer2(Subject childModel)
152
153 {
154
155 childModel.SubEvent+=new Subject.SubEventHandler(Response);
156
157 childModel.SubEvent+=new Subject.SubEventHandler(Response2);
158
159 }
160
161 public abstract void Response();
162
163 public abstract void Response2();
164
165 }
166
167}
168
169//-------------------------------------------------------------------------------------------------------
170
171現在,我們來(lái)針對這個(gè)實(shí)例中的貓大叫這個(gè)引發(fā)事件進(jìn)行解析。
172
173namespace DelegateEvent
174
175{
176
177 /// <summary>
178
179 /// Cat 的摘要說(shuō)明。
180
181 /// 此類(lèi)作為被觀(guān)察者對象
182
183 /// 直接繼承Subject類(lèi)
184
185 /// 使用一個(gè)Cry方法,調用Notify方法起用先前定義的SubEvent事件
186
187 /// </summary>
188
189 public class Cat:Subject
190
191 {
192
193 public Cat()
194
195 {
196
197 //
198
199 // TODO: 在此處添加構造函數邏輯
200
201 //
202
203 }
204
205 public void Cry()
206
207 {
208
209 System.Console.WriteLine("Cat Cry..");
210
211 //調用從ModelBase繼承過(guò)來(lái)的Notify()
212
213 this.Notify();
214
215 }
216
217 }
218
219}
220
221// 這樣一個(gè)被觀(guān)察者對象就完成了。
222
223//--------------------------------------------------------------------------------------------------------------------
224
225被觀(guān)察者對象有了,我們再來(lái)創(chuàng )建具體的觀(guān)察者對象。此例中,有主人,小孩和老鼠對貓的叫聲做出了反應,因此我們可以創(chuàng )建三個(gè)類(lèi),分別對主人、小孩和老鼠進(jìn)行響應。其中,主人和老鼠對應Observer類(lèi),響應其中的一個(gè)事件;而小孩則繼承Observer2類(lèi),響應其中的兩個(gè)事件。
226
227//------------------------------------觀(guān)察者--主人類(lèi)---------------------------------------------------
228
229namespace DelegateEvent
230
231{
232
233 /// <summary>
234
235 /// Master 的摘要說(shuō)明。
236
237 /// </summary>
238
239 public class Master:Observer
240
241 {
242
243 /// <summary>
244
245 /// 構造函數,接受一個(gè)Cat類(lèi)型的對象childModel并強制轉換為基類(lèi)ModelBase變量
246
247 /// 再將childModel傳入到父類(lèi)Observer的構造函數當中,實(shí)現注冊。
248
249 /// </summary>
250
251 /// <param name="childModel"></param>
252
253 public Master(Subject childModel):base(childModel)
254
255 {
256
257
258
259 }
260
261 public override void Response()
262
263 {
264
265 System.Console.WriteLine("主人醒來(lái)");
266
267 }
268
269 }
270
271}
272
273//------------------------------------觀(guān)察者--老鼠類(lèi)-----------------------------------------------------
274
275namespace DelegateEvent
276
277{
278
279 /// <summary>
280
281 /// Mouse 的摘要說(shuō)明。
282
283 /// </summary>
284
285 public class Mouse:Observer
286
287 {
288
289 private string name;
290
291 public Mouse(string name, Subject childModel):base(childModel)
292
293 {
294
295 this.name=name;
296
297 }
298
299
300
301 //覆蓋Observer類(lèi)Response方法
302
303 public override void Response()
304
305 {
306
307 System.Console.WriteLine(this.name+"開(kāi)始逃跑");
308
309 }
310
311 }
312
313}
314
315//于主人類(lèi)不同的是,老鼠類(lèi)的構造函數可以接受一個(gè)字符串參數,這樣可以變的更多樣化
316
317//------------------------------------觀(guān)察者--小孩------------------------------------------------------------
318
319namespace DelegateEvent
320
321{
322
323 /// <summary>
324
325 /// Child 的摘要說(shuō)明。
326
327 /// </summary>
328
329 public class Child:Observer2
330
331 {
332
333 public Child(Subject childBase):base(childBase)
334
335 {
336
337
338
339 }
340
341 public override void Response()
342
343 {
344
345 Console.WriteLine("baby醒來(lái)。。。。");
346
347 }
348
349 public override void Response2()
350
351 {
352
353 Console.WriteLine("開(kāi)始哭鬧。。。。。");
354
355 }
356
357 }
358
359}
360
361//小孩類(lèi)里,由于繼承的是Observer2類(lèi),因此可以響應兩種不同的方法。
362
363在主函數里,定義每個(gè)觀(guān)察者子類(lèi)的對象,由其構造函數接受被觀(guān)察者對象進(jìn)行事件的響應。
364
365namespace DelegateEvent
366
367{
368
369 /// <summary>
370
371 /// SubMain 的摘要說(shuō)明。
372
373 /// </summary>
374
375 public class SubMain
376
377 {
378
379 public SubMain()
380
381 {
382
383
384
385 }
386
387 /// <summary>
388
389 /// 主函數,定義子類(lèi)對象
390
391 /// </summary>
392
393 public static void Main()
394
395 {
396
397 Cat myCat=new Cat();
398
399 Mouse myMouse1=new Mouse("mouse1",myCat);
400
401 Mouse myMouse2=new Mouse("mouse2",myCat);
402
403 Master myMaster=new Master(myCat);
404
405
406
407 Child myLittleMaster=new Child(myCat);
408
409 myCat.Cry();
410
411 }
412
413 }
414
415}
416
417改變一下應用環(huán)境:
老鼠偷油,貓來(lái)捉老鼠,老鼠嚇跑,打碎了油瓶,人被吵醒。
這樣的一個(gè)環(huán)境下,如何使用觀(guān)察者模式呢?
首先區分,誰(shuí)是一整串事件的引發(fā)者,可以分析是老鼠,老鼠偷油這件事情引發(fā)了一系列事件。
貓作為老鼠的觀(guān)察者,當老鼠偷油這件事情發(fā)生以后,觸發(fā)貓捉老鼠的事件,而下面思維開(kāi)始混亂,因為老鼠逃跑,打翻油瓶這件事按理論來(lái)說(shuō)應該不是直接由老鼠偷油這件事情引發(fā)的,而是由貓捉老鼠這件事情。因此在貓捉老鼠,老鼠逃跑的事件中,又似乎是貓是被觀(guān)察者,而老鼠是觀(guān)察者。但這樣理解的話(huà),是不是就形成一種循環(huán)了亞。
但細細想來(lái),上面這個(gè)問(wèn)題又是自欺欺人,因為首先觀(guān)察者模式是希望實(shí)現一個(gè)對象的狀態(tài)發(fā)生改變時(shí),所有依賴(lài)于它的對象都得到通知并自動(dòng)刷新。
從上面情形來(lái)看,老鼠逃跑只是這個(gè)鏈上的一個(gè)節點(diǎn),而這個(gè)節點(diǎn)的事件發(fā)起人正是被觀(guān)察者,因此又出現下列問(wèn)題,被觀(guān)察者能否依賴(lài)于其本身呢?只要是能依賴(lài),這樣一個(gè)情形,使用觀(guān)察者模性就是合理的。但是假使這樣可行的話(huà),那么觀(guān)察者和被觀(guān)察者之間是否又沒(méi)有了清晰的界限,加大了對象之間的耦合關(guān)系,這是不是又違背OO思想?希望大家給點(diǎn)意見(jiàn)。
上述情形實(shí)現代碼如下:
result:
UML關(guān)系圖: