转载:Observer设计模式
1Observer设计模式#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
38using System;
39using System.Collections.Generic;
40using System.Text;
41
42namespace 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
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
38using System;
39using System.Collections.Generic;
40using System.Text;
41
42namespace 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