观察者模式是设计模式中行为模型的一种,是定义对象间的一种一对多的依赖关系,以便当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并自动刷新。
观察者模式是设计模式中行为模型的一种,是定义对象间的一种一对多的依赖关系,以便当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并自动刷新。
典型的应用情形为:
夜里有一只猫大叫了一声,同处一屋的老鼠接受到了猫大叫的信息,于是开始逃跑。同样,主人听到了,被吵醒了;小孩子听到了,被吓哭了。
实现代码如下:


1
using System;
2
3
namespace 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
81
namespace 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
135
namespace 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
173
namespace 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
229
namespace 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
275
namespace 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
319
namespace 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
365
namespace 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思想?希望大家给点意见。
上述情形实现代码如下:


1
using System;
2
using System.Collections.Generic;
3
using System.Text;
4
5
namespace 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
93
using System;
94
using System.Collections.Generic;
95
using System.Text;
96
97
namespace 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
143
using System;
144
using System.Collections.Generic;
145
using System.Text;
146
147
namespace 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
225
using System;
226
using System.Collections.Generic;
227
using System.Text;
228
229
namespace 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
261
using System;
262
using System.Collections.Generic;
263
using System.Text;
264
265
namespace 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
--程序入口点
287
using System;
288
using System.Collections.Generic;
289
using System.Text;
290
291
namespace 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关系图:
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· .NET周刊【3月第1期 2025-03-02】
· [AI/GPT/综述] AI Agent的设计模式综述