转载:Observer设计模式
1![]()
Observer设计模式#region Observer设计模式
2![]()
/**//*
3
* 假设热水器由三部分组成:热水器、警报器、显示器,它们来自于不同厂商并进行了组装。那么应该是热水器仅仅负责烧水,它不能发出警报也不能显示水温;
4
* 在水烧开时由警报器发出警报、显示器显示提示和水温。
5
*
6
* Observer设计模式中主要包括如下两类对象:
7
* (1)Subject: 监视对象,它往往包含着其它对象所感兴趣的内容。在本范例中,热水器就是一个监视对象,它包含的其它对象所感兴趣的内容,就是temprature
8
* 字段,当这个字段的值快到100时,会不断把数据发给监视它的对象。
9
* (2)Observer: 监视者,它监视Subject,当Subject中的某件事发生的时候,会告知Observer,而Observer则会采取相应的行动。在本范例中,Observer有警报器
10
* 和显示器,它们采取的行动分别是发出警报和显示水温。
11
*
12
* 在本例中,事情发生的顺序应该是这样的:
13
* (1)警报器和显示器告诉热水器,它对它的温度比较感兴趣(注册)。
14
* (2)热水器知道后保留对警报器和显示器的引用。
15
* (3)热水器进行烧水这一动作,当水温超过95度时,通过对警报器和显示器的引用,自动调用警报器的MakeAlert()方法、显示器的ShowMsg()方法。
16
*
17
* 类似这样的例子是很多的,GOF对它进行了抽象,称为Observer设计模式:Observer设计模式是为了定义对象间的一种一对多的依赖关系,以便于当一个对象的
18
* 状态改变时,其它依赖于它的对象会被自动告知并更新。Observer模式是一种松耦合的设计模式。
19
*
20
* .Net Framework中的委托与事件
21
* 尽管上面的范例很好第完成了我们想要完成的工作,但是我们不仅疑惑:为什么.Net Framework中的事件模型与上面的不同?为什么有很多的EventArgs参数?
22
* 在回答上面的问题之前,我们先搞懂.Net Framework的编码规范:
23
* (1)委托类型的名称都应该以EventHandler结束。
24
* (2)委托的原型定义:有一个void返回值,并接受两个输入参数:一个Object类型,一个EventArgs类型(或继承自EventArgs)。
25
* (3)事件的命名为:委托去掉EventHandler之后剩余的部分。
26
* (4)继承自EventArgs的类型应该以EventArgs结尾。
27
*
28
* 再做一下说明:
29
* (1)委托声明原型中的Object类型的参数代表了Subject,也就是监视对象,在本例中是Heater(热水器)。回调函数(比如 Alarm的MakeAlert)可以通过它
30
* 访问触发事件的对象(Heater)。
31
* (2)EventArgs对象包含了Observer所感兴趣的数据,在本例中是temperature。
32
*
33
* 上面这些其实不仅仅是为了编码规范而已,这样也使得程序有更大的灵活性。比如说,我们不光想获得热水器的温度,还想在Observer端(警报器或者显示器)
34
* 方法中获得它的生产日期、型号、价格,那么委托和方法的声明都会变得麻烦,而如果我们将热水器的引用传给警报器方法,就可以在方法中直接访问热水器了。
35
*
36
*/
37
#endregion
38
using System;
39
using System.Collections.Generic;
40
using System.Text;
41![]()
42
namespace ObserverMode
43![]()
![]()
{
44![]()
非Observer设计模式#region 非Observer设计模式
45
//class Heater
46
//{
47
// private int temperature;
48
49
// //烧水
50
// public void BoilWater()
51
// {
52
// for (int i = 0; i <= 100; i++)
53
// {
54
// temperature = i;
55
// if (temperature > 95)
56
// {
57
// MakeAlert(temperature);
58
// ShowMsg(temperature);
59
// }
60
// }
61
// }
62![]()
63
// //发出语音警报
64
// private void MakeAlert(int param)
65
// {
66
// Console.WriteLine("Alarm:嘀嘀嘀,水已经{0}度了。", param);
67
// }
68![]()
69
// //显示水温
70
// private void ShowMsg(int param)
71
// {
72
// Console.WriteLine("Display:水快开了,当前温度:{0}度。", param);
73
// }
74
//}
75![]()
76
//class Program
77
//{
78
// static void Main(string[] args)
79
// {
80
// Heater ht = new Heater();
81
// ht.BoilWater();
82
// Console.ReadLine();
83
// }
84
//}
85
#endregion
86![]()
87![]()
Observer设计模式#region Observer设计模式
88![]()
89![]()
/**/////热水器
90
//public class Heater
91
//{
92
// private int temperature;
93
// public delegate void BoilHandler(int param); //声明委托
94
// public event BoilHandler BoilEvent; //声明事件
95
96
// //烧水
97
// public void BoilWater()
98
// {
99
// for (int i = 0; i <= 100; i++)
100
// {
101
// temperature = i;
102![]()
103
// if (temperature > 95)
104
// {
105
// if (BoilEvent != null) //如果有对象注册
106
// {
107
// BoilEvent(temperature); //调用所有注册对象的方法
108
// }
109
// }
110
// }
111
// }
112
//}
113![]()
114![]()
/**/////警报器
115
//public class Alarm
116
//{
117
// public void MakeAlert(int param)
118
// {
119
// Console.WriteLine("Alarm:嘀嘀嘀,水已经{0}度。", param);
120
// }
121
//}
122![]()
123![]()
/**/////显示器
124
//public class Display
125
//{
126
// public static void ShowMsg(int param) //静态方法
127
// {
128
// Console.WriteLine("Display:水已烧开,当前温度:{0}度。", param);
129
// }
130
//}
131![]()
132
//class Program
133
//{
134
// static void Main(string[] args)
135
// {
136
// Heater heater = new Heater();
137
// Alarm alarm = new Alarm();
138![]()
139
// heater.BoilEvent += alarm.MakeAlert; //注册方法
140
// heater.BoilEvent += (new Alarm()).MakeAlert; //给匿名对象注册方法
141
// heater.BoilEvent += Display.ShowMsg; //注册静态方法
142
// heater.BoilWater(); //烧水,会自动调用注册对象的方法
143
// Console.ReadLine();
144
// }
145
//}
146
#endregion
147![]()
148![]()
符合.Net Framework规范的Observer设计模式#region 符合.Net Framework规范的Observer设计模式
149![]()
150
//热水器
151
public class Heater
152![]()
{
153
private int temperature;
154
public string type = "RealFile 001"; //添加型号作为演示
155
public string area = "China Xian"; //添加产地作为演示
156![]()
157
//定义BoiledEventArgs类,传递给Observer所感兴趣的信息
158
public class BoiledEventArgs : EventArgs
159![]()
{
160
public readonly int temperature;
161
public BoiledEventArgs(int temperature)
162![]()
{
163
this.temperature = temperature;
164
}
165
}
166![]()
167
//声明委托
168
public delegate void BoiledEventHandler(Object sender, BoiledEventArgs e);
169
public event BoiledEventHandler Boiled; //声明事件
170![]()
171
//可以供继承自Heater的类重写,以便继承类拒绝其它对象对它的监视
172
protected virtual void OnBolied(BoiledEventArgs e)
173![]()
{
174
if (Boiled != null)
175![]()
{
176
Boiled(this, e);
177
}
178
}
179![]()
180
//烧水
181
public void BoilWater()
182![]()
{
183
for (int i = 0; i <= 100; i++)
184![]()
{
185
temperature = i;
186
if (temperature > 95)
187![]()
{
188
//建立BoiledEventArgs对象。
189
BoiledEventArgs e = new BoiledEventArgs(temperature);
190
OnBolied(e); //调用OnBoiled方法
191
}
192
}
193
}
194
}
195![]()
196
//警报器
197
public class Alarm
198![]()
{
199
public void MakeAlert(Object sender, Heater.BoiledEventArgs e)
200![]()
{
201
Heater heater = (Heater)sender;
202
//访问sender中的公共字段
203
Console.WriteLine("Alarm:{0} - {1}:", heater.area, heater.type);
204
Console.WriteLine("Alarm:嘀嘀嘀,水已经{0}度了:", e.temperature);
205
Console.WriteLine();
206
}
207
}
208![]()
209
//显示器
210
public class Display
211![]()
{
212
public static void ShowMsg(object sender, Heater.BoiledEventArgs e)
213![]()
{
214
Heater heater = (Heater)sender;
215
Console.WriteLine("Display:{0} - {1}:", heater.area, heater.type);
216
Console.WriteLine("Display:水快烧开了,当前温度:{0}度。", e.temperature);
217
Console.WriteLine();
218
}
219
}
220![]()
221
class Program
222![]()
{
223
static void Main(string[] args)
224![]()
{
225
Heater heater = new Heater();
226
Alarm alarm = new Alarm();
227![]()
228
heater.Boiled += alarm.MakeAlert; //注册方法
229
heater.Boiled += (new Alarm()).MakeAlert; //给匿名对象注册方法
230
heater.Boiled += new Heater.BoiledEventHandler(alarm.MakeAlert); //也可以这么注册
231
heater.Boiled += Display.ShowMsg; //注册静态方法
232
heater.BoilWater();
233
Console.ReadLine();
234
}
235
}
236![]()
237
#endregion
238
}
239![]()

Observer设计模式#region Observer设计模式2

/**//*3
* 假设热水器由三部分组成:热水器、警报器、显示器,它们来自于不同厂商并进行了组装。那么应该是热水器仅仅负责烧水,它不能发出警报也不能显示水温;4
* 在水烧开时由警报器发出警报、显示器显示提示和水温。5
* 6
* Observer设计模式中主要包括如下两类对象:7
* (1)Subject: 监视对象,它往往包含着其它对象所感兴趣的内容。在本范例中,热水器就是一个监视对象,它包含的其它对象所感兴趣的内容,就是temprature8
* 字段,当这个字段的值快到100时,会不断把数据发给监视它的对象。9
* (2)Observer: 监视者,它监视Subject,当Subject中的某件事发生的时候,会告知Observer,而Observer则会采取相应的行动。在本范例中,Observer有警报器10
* 和显示器,它们采取的行动分别是发出警报和显示水温。11
* 12
* 在本例中,事情发生的顺序应该是这样的:13
* (1)警报器和显示器告诉热水器,它对它的温度比较感兴趣(注册)。14
* (2)热水器知道后保留对警报器和显示器的引用。15
* (3)热水器进行烧水这一动作,当水温超过95度时,通过对警报器和显示器的引用,自动调用警报器的MakeAlert()方法、显示器的ShowMsg()方法。16
* 17
* 类似这样的例子是很多的,GOF对它进行了抽象,称为Observer设计模式:Observer设计模式是为了定义对象间的一种一对多的依赖关系,以便于当一个对象的18
* 状态改变时,其它依赖于它的对象会被自动告知并更新。Observer模式是一种松耦合的设计模式。19
* 20
* .Net Framework中的委托与事件21
* 尽管上面的范例很好第完成了我们想要完成的工作,但是我们不仅疑惑:为什么.Net Framework中的事件模型与上面的不同?为什么有很多的EventArgs参数?22
* 在回答上面的问题之前,我们先搞懂.Net Framework的编码规范:23
* (1)委托类型的名称都应该以EventHandler结束。24
* (2)委托的原型定义:有一个void返回值,并接受两个输入参数:一个Object类型,一个EventArgs类型(或继承自EventArgs)。25
* (3)事件的命名为:委托去掉EventHandler之后剩余的部分。26
* (4)继承自EventArgs的类型应该以EventArgs结尾。27
* 28
* 再做一下说明:29
* (1)委托声明原型中的Object类型的参数代表了Subject,也就是监视对象,在本例中是Heater(热水器)。回调函数(比如 Alarm的MakeAlert)可以通过它30
* 访问触发事件的对象(Heater)。31
* (2)EventArgs对象包含了Observer所感兴趣的数据,在本例中是temperature。32
* 33
* 上面这些其实不仅仅是为了编码规范而已,这样也使得程序有更大的灵活性。比如说,我们不光想获得热水器的温度,还想在Observer端(警报器或者显示器)34
* 方法中获得它的生产日期、型号、价格,那么委托和方法的声明都会变得麻烦,而如果我们将热水器的引用传给警报器方法,就可以在方法中直接访问热水器了。35
* 36
*/37
#endregion38
using System;39
using System.Collections.Generic;40
using System.Text;41

42
namespace ObserverMode43


{44

非Observer设计模式#region 非Observer设计模式45
//class Heater46
//{47
// private int temperature;48
49
// //烧水50
// public void BoilWater()51
// {52
// for (int i = 0; i <= 100; i++)53
// {54
// temperature = i;55
// if (temperature > 95)56
// {57
// MakeAlert(temperature);58
// ShowMsg(temperature);59
// }60
// }61
// }62

63
// //发出语音警报64
// private void MakeAlert(int param)65
// {66
// Console.WriteLine("Alarm:嘀嘀嘀,水已经{0}度了。", param);67
// }68

69
// //显示水温70
// private void ShowMsg(int param)71
// {72
// Console.WriteLine("Display:水快开了,当前温度:{0}度。", param);73
// }74
//}75

76
//class Program77
//{78
// static void Main(string[] args)79
// {80
// Heater ht = new Heater();81
// ht.BoilWater();82
// Console.ReadLine();83
// }84
//}85
#endregion86

87

Observer设计模式#region Observer设计模式88

89

/**/////热水器90
//public class Heater91
//{92
// private int temperature;93
// public delegate void BoilHandler(int param); //声明委托94
// public event BoilHandler BoilEvent; //声明事件95
96
// //烧水97
// public void BoilWater()98
// {99
// for (int i = 0; i <= 100; i++)100
// {101
// temperature = i;102

103
// if (temperature > 95)104
// {105
// if (BoilEvent != null) //如果有对象注册106
// {107
// BoilEvent(temperature); //调用所有注册对象的方法108
// }109
// }110
// }111
// }112
//}113

114

/**/////警报器115
//public class Alarm116
//{117
// public void MakeAlert(int param)118
// {119
// Console.WriteLine("Alarm:嘀嘀嘀,水已经{0}度。", param);120
// }121
//}122

123

/**/////显示器124
//public class Display125
//{126
// public static void ShowMsg(int param) //静态方法127
// {128
// Console.WriteLine("Display:水已烧开,当前温度:{0}度。", param);129
// }130
//}131

132
//class Program133
//{134
// static void Main(string[] args)135
// {136
// Heater heater = new Heater();137
// Alarm alarm = new Alarm();138

139
// heater.BoilEvent += alarm.MakeAlert; //注册方法140
// heater.BoilEvent += (new Alarm()).MakeAlert; //给匿名对象注册方法141
// heater.BoilEvent += Display.ShowMsg; //注册静态方法142
// heater.BoilWater(); //烧水,会自动调用注册对象的方法143
// Console.ReadLine();144
// }145
//}146
#endregion147

148

符合.Net Framework规范的Observer设计模式#region 符合.Net Framework规范的Observer设计模式149

150
//热水器151
public class Heater152

{153
private int temperature;154
public string type = "RealFile 001"; //添加型号作为演示155
public string area = "China Xian"; //添加产地作为演示156

157
//定义BoiledEventArgs类,传递给Observer所感兴趣的信息158
public class BoiledEventArgs : EventArgs159

{160
public readonly int temperature;161
public BoiledEventArgs(int temperature)162

{163
this.temperature = temperature;164
}165
}166

167
//声明委托168
public delegate void BoiledEventHandler(Object sender, BoiledEventArgs e);169
public event BoiledEventHandler Boiled; //声明事件170

171
//可以供继承自Heater的类重写,以便继承类拒绝其它对象对它的监视172
protected virtual void OnBolied(BoiledEventArgs e)173

{174
if (Boiled != null)175

{176
Boiled(this, e);177
}178
}179

180
//烧水181
public void BoilWater()182

{183
for (int i = 0; i <= 100; i++)184

{185
temperature = i;186
if (temperature > 95)187

{ 188
//建立BoiledEventArgs对象。189
BoiledEventArgs e = new BoiledEventArgs(temperature);190
OnBolied(e); //调用OnBoiled方法191
}192
}193
}194
}195

196
//警报器197
public class Alarm198

{199
public void MakeAlert(Object sender, Heater.BoiledEventArgs e)200

{201
Heater heater = (Heater)sender;202
//访问sender中的公共字段203
Console.WriteLine("Alarm:{0} - {1}:", heater.area, heater.type);204
Console.WriteLine("Alarm:嘀嘀嘀,水已经{0}度了:", e.temperature);205
Console.WriteLine();206
}207
}208

209
//显示器210
public class Display211

{212
public static void ShowMsg(object sender, Heater.BoiledEventArgs e)213

{214
Heater heater = (Heater)sender;215
Console.WriteLine("Display:{0} - {1}:", heater.area, heater.type);216
Console.WriteLine("Display:水快烧开了,当前温度:{0}度。", e.temperature);217
Console.WriteLine();218
}219
}220

221
class Program222

{223
static void Main(string[] args)224

{225
Heater heater = new Heater();226
Alarm alarm = new Alarm();227

228
heater.Boiled += alarm.MakeAlert; //注册方法229
heater.Boiled += (new Alarm()).MakeAlert; //给匿名对象注册方法230
heater.Boiled += new Heater.BoiledEventHandler(alarm.MakeAlert); //也可以这么注册231
heater.Boiled += Display.ShowMsg; //注册静态方法232
heater.BoilWater();233
Console.ReadLine();234
}235
}236

237
#endregion238
}239

浙公网安备 33010602011771号