亂點“觀察者模式"
觀察者模式是設計模式中行為模型的一種,是定義對象間的一種一對多的依賴關系,以便當一個對象的狀態發生改變時,所有依賴于它的對象都得到通知并自動刷新。
觀察者模式是設計模式中行為模型的一種,是定義對象間的一種一對多的依賴關系,以便當一個對象的狀態發生改變時,所有依賴于它的對象都得到通知并自動刷新。
典型的應用情形為:
夜里有一只貓大叫了一聲,同處一屋的老鼠接受到了貓大叫的信息,于是開始逃跑。同樣,主人聽到了,被吵醒了;小孩子聽到了,被嚇哭了。
實現代碼如下:
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關系圖:
作者:jillzhang
出處:http://jillzhang.cnblogs.com/
本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,否則保留追究法律責任的權利。
出處:http://jillzhang.cnblogs.com/
本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,否則保留追究法律責任的權利。

浙公網安備 33010602011771號