乱点“观察者模式"
观察者模式是设计模式中行为模型的一种,是定义对象间的一种一对多的依赖关系,以便当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并自动刷新。
观察者模式是设计模式中行为模型的一种,是定义对象间的一种一对多的依赖关系,以便当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并自动刷新。
典型的应用情形为:
夜里有一只猫大叫了一声,同处一屋的老鼠接受到了猫大叫的信息,于是开始逃跑。同样,主人听到了,被吵醒了;小孩子听到了,被吓哭了。
实现代码如下:
1using System;
2
3namespace DelegateEvent
4
5{
6
7 /**//// <summary>
8
9 /// Subject 的摘要说明。
10
11 /// 被观察者抽象基类
12
13 /// 所有被观察者对象都继承此类
14
15 /// 做为抽象基类,此类不允许直接进行实例化
16
17 /// 此类中首先定义委托
18
19 /// 再有委托定义事件
20
21 /// 然后创立与委托想关联的方法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 /// 创建一个委托
44
45 /// </summary>
46
47 public delegate void SubEventHandler();
48
49 /**//// <summary>
50
51 /// 根据SubEventHandler创建一个事件
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被观察者基类完成后我们再来创建观察者基类Observer.
80
81namespace DelegateEvent
82
83{
84
85 /**//// <summary>
86
87 /// Observer 的摘要说明。
88
89 /// 观察者抽象基类
90
91 /// 所有观察者对象都由此类派生
92
93 /// 使用此类进行对事件的注册
94
95 /// 并和事件的方法关联
96
97 /// 另外定义了一个抽象方法Response
98
99 /// 可以由子类来进行覆盖
100
101 /// </summary>
102
103 public abstract class Observer
104
105 {
106
107 public Observer(Subject childModel)
108
109 {
110
111 //注册SubEvent事件通过SubEventHandler委托和Response方法关联
112
113 //子类通过调用此构造函数完成事件的注册
114
115 childModel.SubEvent+=new Subject.SubEventHandler(Response);
116
117 }
118
119
120
121 /**//// <summary>
122
123 /// 抽象方法,用于引发事件
124
125 /// </summary>
126
127 public abstract void Response();
128
129 }
130
131}
132
133同理,我们还可以继续创建另一个观察者基类,用来响应不同的事件的方法。
134
135namespace DelegateEvent
136
137{
138
139 /**//// <summary>
140
141 /// Observer2 的摘要说明。
142
143 /// 注册了两个事件的方法。
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现在,我们来针对这个实例中的猫大叫这个引发事件进行解析。
172
173namespace DelegateEvent
174
175{
176
177 /**//// <summary>
178
179 /// Cat 的摘要说明。
180
181 /// 此类作为被观察者对象
182
183 /// 直接继承Subject类
184
185 /// 使用一个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继承过来的Notify()
212
213 this.Notify();
214
215 }
216
217 }
218
219}
220
221// 这样一个被观察者对象就完成了。
222
223//--------------------------------------------------------------------------------------------------------------------
224
225被观察者对象有了,我们再来创建具体的观察者对象。此例中,有主人,小孩和老鼠对猫的叫声做出了反应,因此我们可以创建三个类,分别对主人、小孩和老鼠进行响应。其中,主人和老鼠对应Observer类,响应其中的一个事件;而小孩则继承Observer2类,响应其中的两个事件。
226
227//------------------------------------观察者--主人类---------------------------------------------------
228
229namespace DelegateEvent
230
231{
232
233 /**//// <summary>
234
235 /// Master 的摘要说明。
236
237 /// </summary>
238
239 public class Master:Observer
240
241 {
242
243 /**//// <summary>
244
245 /// 构造函数,接受一个Cat类型的对象childModel并强制转换为基类ModelBase变量
246
247 /// 再将childModel传入到父类Observer的构造函数当中,实现注册。
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("主人醒来");
266
267 }
268
269 }
270
271}
272
273//------------------------------------观察者--老鼠类-----------------------------------------------------
274
275namespace DelegateEvent
276
277{
278
279 /**//// <summary>
280
281 /// Mouse 的摘要说明。
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类Response方法
302
303 public override void Response()
304
305 {
306
307 System.Console.WriteLine(this.name+"开始逃跑");
308
309 }
310
311 }
312
313}
314
315//于主人类不同的是,老鼠类的构造函数可以接受一个字符串参数,这样可以变的更多样化
316
317//------------------------------------观察者--小孩------------------------------------------------------------
318
319namespace DelegateEvent
320
321{
322
323 /**//// <summary>
324
325 /// Child 的摘要说明。
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醒来。。。。");
346
347 }
348
349 public override void Response2()
350
351 {
352
353 Console.WriteLine("开始哭闹。。。。。");
354
355 }
356
357 }
358
359}
360
361//小孩类里,由于继承的是Observer2类,因此可以响应两种不同的方法。
362
363在主函数里,定义每个观察者子类的对象,由其构造函数接受被观察者对象进行事件的响应。
364
365namespace DelegateEvent
366
367{
368
369 /**//// <summary>
370
371 /// SubMain 的摘要说明。
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 /// 主函数,定义子类对象
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
改变一下应用环境:
老鼠偷油,猫来捉老鼠,老鼠吓跑,打碎了油瓶,人被吵醒。
这样的一个环境下,如何使用观察者模式呢?
首先区分,谁是一整串事件的引发者,可以分析是老鼠,老鼠偷油这件事情引发了一系列事件。
猫作为老鼠的观察者,当老鼠偷油这件事情发生以后,触发猫捉老鼠的事件,而下面思维开始混乱,因为老鼠逃跑,打翻油瓶这件事按理论来说应该不是直接由老鼠偷油这件事情引发的,而是由猫捉老鼠这件事情。因此在猫捉老鼠,老鼠逃跑的事件中,又似乎是猫是被观察者,而老鼠是观察者。但这样理解的话,是不是就形成一种循环了亚。
但细细想来,上面这个问题又是自欺欺人,因为首先观察者模式是希望实现一个对象的状态发生改变时,所有依赖于它的对象都得到通知并自动刷新。
从上面情形来看,老鼠逃跑只是这个链上的一个节点,而这个节点的事件发起人正是被观察者,因此又出现下列问题,被观察者能否依赖于其本身呢?只要是能依赖,这样一个情形,使用观察者模性就是合理的。但是假使这样可行的话,那么观察者和被观察者之间是否又没有了清晰的界限,加大了对象之间的耦合关系,这是不是又违背OO思想?希望大家给点意见。
上述情形实现代码如下:
1using System;
2using System.Collections.Generic;
3using System.Text;
4
5namespace ConsoleApplication3
6{
7 /**//// <summary>
8 /// 被观察者的抽象类
9 /// </summary>
10 public class Model
11 {
12 /**//// <summary>
13 /// 定义一个返回为空的委托
14 /// </summary>
15 public delegate void ModelDelegate();
16 /**//// <summary>
17 /// 通知事件
18 /// </summary>
19 event ModelDelegate _notifyEvent;
20 /**//// <summary>
21 /// 通知事件
22 /// </summary>
23 public event ModelDelegate NotifyEvent
24 {
25 add
26 {
27 this._notifyEvent += value;
28 }
29 remove
30 {
31 this._notifyEvent -= value;
32 }
33 }
34 /**//// <summary>
35 /// 通知方法
36 /// </summary>
37 public void Notify()
38 {
39 this._notifyEvent();
40 }
41 List<Observer> _observers = new List<Observer>();
42 /**//// <summary>
43 /// 构造
44 /// </summary>
45 public Model()
46 {
47
48 }
49
50 /**//// <summary>
51 /// 观察者集合
52 /// </summary>
53 public List<Observer> ObserversCollection
54 {
55 get
56 {
57 return _observers;
58 }
59 set
60 {
61 _observers = value;
62 }
63 }
64
65 /**//// <summary>
66 /// 注册观察者
67 /// </summary>
68 /// <param name="observer"></param>
69 public void RegisterObserver(Observer observer)
70 {
71 if (observer != null)
72 {
73 this.ObserversCollection.Add(observer);
74 }
75 }
76 /**//// <summary>
77 /// 注销观察者
78 /// </summary>
79 /// <param name="observer"></param>
80 public void DetachObserver(Observer observer)
81 {
82 if (observer != null)
83 {
84 this.ObserversCollection.Remove(observer);
85 }
86 }
87
88 }
89}
90
91
92
93using System;
94using System.Collections.Generic;
95using System.Text;
96
97namespace ConsoleApplication3
98{
99 public abstract class Observer
100 {
101 private Model _model;
102
103 Contructor#region Contructor
104 /**//// <summary>
105 /// 构造函数
106 /// </summary>
107 /// <param name="model"></param>
108 public Observer(Model model)
109 {
110 this._model = model;
111 this._model.NotifyEvent += new Model.ModelDelegate(DoSomeThing);
112 }
113 #endregion
114
115
116 Public Field#region Public Field
117 /**//// <summary>
118 /// 被观察者
119 /// </summary>
120 public Model ObserverdModel
121 {
122 get
123 {
124 return _model;
125 }
126 set
127 {
128 _model = value;
129 }
130 }
131 #endregion
132
133 Method#region Method
134 /**//// <summary>
135 /// 观察者得到通知后的操作
136 /// </summary>
137 public abstract void DoSomeThing();
138 #endregion
139 }
140}
141
142
143using System;
144using System.Collections.Generic;
145using System.Text;
146
147namespace ConsoleApplication3
148{
149 public enum RatStateEnmu
150 {
151 Stealing,
152 Running,
153 StrickDownBottom,
154 Tackled
155 }
156 public class Rat:Model
157 {
158 bool _seeCat;
159 RatStateEnmu _state;
160 public RatStateEnmu State
161 {
162 get
163 {
164 return _state;
165 }
166 set
167 {
168 _state = value;
169 }
170 }
171 EventHandler _seeCatHandler;
172 public event EventHandler SeeCatComming
173 {
174 add
175 {
176 _seeCatHandler += value;
177 }
178 remove
179 {
180 _seeCatHandler -= value;
181 }
182 }
183 void Run(Object sender,EventArgs e)
184 {
185 Console.WriteLine("Rat:不好,大傻猫过来了,赶紧跑!\n");
186 _state = RatStateEnmu.Running;
187 if (_seeCatHandler != null)
188 {
189 _seeCatHandler(sender,e);
190 }
191 }
192 /**//// <summary>
193 /// 是否看见了猫
194 /// </summary>
195 public bool SeeCat
196 {
197 get
198 {
199 return _seeCat;
200 }
201 set
202 {
203 _seeCat = value;
204 Run(this, new EventArgs());
205 }
206 }
207 public void StealOil()
208 {
209 Console.WriteLine("Rat:噔噔噔噔,我是一只小老鼠,自由的小老鼠,我赛,好大一桶油,够我吃1年的了。我要把它搬回家!\n");
210 Console.WriteLine("Rat:等等,听说最近死猫经常出现,小心点为妙!\n");
211 this._state = RatStateEnmu.Stealing;
212 this.Notify();
213 }
214
215 public void StrickDowmBottle()
216 {
217 Console.WriteLine("system:哗啦啦,油瓶子被打翻了!\n");
218 this._state = RatStateEnmu.StrickDownBottom;
219 this.Notify();
220 }
221 }
222}
223
224
225using System;
226using System.Collections.Generic;
227using System.Text;
228
229namespace ConsoleApplication3
230{
231 /**//// <summary>
232 /// 观察者-猫
233 /// </summary>
234 public class Cat:Observer
235 {
236 private Rat _rat;
237
238 public Cat(Rat rat) : base(rat)
239 {
240 this._rat = rat;
241 this._rat.SeeCatComming += new EventHandler(_rat_SeeCatComming);
242 }
243
244 void _rat_SeeCatComming(object sender, EventArgs e)
245 {
246 this._rat.StrickDowmBottle();
247 }
248
249 public override void DoSomeThing()
250 {
251 if (_rat.State== RatStateEnmu.Stealing)
252 {
253 Console.WriteLine("cat:谁打扰了我的美梦,原来是你这个臭老鼠,耽误你猫大爷的休息,我要吃了你!\n");
254 this._rat.SeeCat = true;
255 }
256 }
257 }
258}
259
260
261using System;
262using System.Collections.Generic;
263using System.Text;
264
265namespace ConsoleApplication3
266{
267 public class Person:Observer
268 {
269 Rat rat;
270 public Person(Rat rat)
271 : base(rat)
272 {
273 this.rat = rat;
274 Console.WriteLine("Person:呼噜呼噜,昨天加班到3点,今天睡得真香!\n");
275 }
276 public override void DoSomeThing()
277 {
278 if (rat.State == RatStateEnmu.StrickDownBottom)
279 {
280 Console.WriteLine("Person:这是干什么呢亚,噼哩啪啦的,把我都给吵醒了\n");
281 }
282 }
283 }
284}
285
286--程序入口点
287using System;
288using System.Collections.Generic;
289using System.Text;
290
291namespace ConsoleApplication3
292{
293 class Program
294 {
295 static void Main(string[] args)
296 {
297 Rat rat = new Rat();
298 Person p = new Person(rat);
299 Cat cat = new Cat(rat);
300 rat.StealOil();
301 Console.Read();
302 }
303 }
304}
305
306
result:
UML关系图:
作者:jillzhang
出处:http://jillzhang.cnblogs.com/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
出处:http://jillzhang.cnblogs.com/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。