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

3
namespace DelegateEvent4

5


{6

7

/**//// <summary>8

9
/// Subject 的摘要说明。10

11
/// 被观察者抽象基类12

13
/// 所有被观察者对象都继承此类14

15
/// 做为抽象基类,此类不允许直接进行实例化16

17
/// 此类中首先定义委托18

19
/// 再有委托定义事件20

21
/// 然后创立与委托想关联的方法Notify22

23
/// </summary>24

25
public abstract class Subject26

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 DelegateEvent82

83


{84

85

/**//// <summary>86

87
/// Observer 的摘要说明。88

89
/// 观察者抽象基类90

91
/// 所有观察者对象都由此类派生92

93
/// 使用此类进行对事件的注册94

95
/// 并和事件的方法关联96

97
/// 另外定义了一个抽象方法Response98

99
/// 可以由子类来进行覆盖100

101
/// </summary>102

103
public abstract class Observer104

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 DelegateEvent136

137


{138

139

/**//// <summary>140

141
/// Observer2 的摘要说明。142

143
/// 注册了两个事件的方法。144

145
/// </summary>146

147
public abstract class Observer2148

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 DelegateEvent174

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:Subject190

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 DelegateEvent230

231


{232

233

/**//// <summary>234

235
/// Master 的摘要说明。236

237
/// </summary>238

239
public class Master:Observer240

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 DelegateEvent276

277


{278

279

/**//// <summary>280

281
/// Mouse 的摘要说明。282

283
/// </summary>284

285
public class Mouse:Observer286

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 DelegateEvent320

321


{322

323

/**//// <summary>324

325
/// Child 的摘要说明。326

327
/// </summary>328

329
public class Child:Observer2330

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 DelegateEvent366

367


{368

369

/**//// <summary>370

371
/// SubMain 的摘要说明。372

373
/// </summary>374

375
public class SubMain376

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 ConsoleApplication36


{7

/**//// <summary>8
/// 被观察者的抽象类9
/// </summary>10
public class Model11

{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 NotifyEvent24

{25
add26

{27
this._notifyEvent += value;28
}29
remove30

{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> ObserversCollection54

{55
get56

{57
return _observers;58
}59
set60

{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 ConsoleApplication398


{99
public abstract class Observer100

{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
#endregion114

115

116

Public Field#region Public Field117

/**//// <summary>118
/// 被观察者119
/// </summary>120
public Model ObserverdModel121

{122
get123

{124
return _model;125
}126
set127

{128
_model = value;129
}130
}131
#endregion132

133

Method#region Method134

/**//// <summary>135
/// 观察者得到通知后的操作136
/// </summary>137
public abstract void DoSomeThing(); 138
#endregion139
}140
}141

142

143
using System;144
using System.Collections.Generic;145
using System.Text;146

147
namespace ConsoleApplication3148


{149
public enum RatStateEnmu150

{151
Stealing,152
Running,153
StrickDownBottom,154
Tackled155
}156
public class Rat:Model157

{158
bool _seeCat;159
RatStateEnmu _state;160
public RatStateEnmu State161

{162
get163

{164
return _state;165
}166
set167

{168
_state = value;169
}170
}171
EventHandler _seeCatHandler; 172
public event EventHandler SeeCatComming173

{174
add175

{176
_seeCatHandler += value;177
}178
remove179

{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 SeeCat196

{197
get198

{199
return _seeCat;200
}201
set202

{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 ConsoleApplication3230


{231

/**//// <summary>232
/// 观察者-猫233
/// </summary>234
public class Cat:Observer235

{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 ConsoleApplication3266


{267
public class Person:Observer268

{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 ConsoleApplication3292


{293
class Program294

{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关系图: