14委托和事件在观察者模式中更好的写法
设计智能汽车,当后面车与前方车小于50米的时候,后面车语音报警,仪表盘显示报警信息,并收到前方车的相关信息。
□ 思路
● 前方车看作是被监视对象,后方车为观察者Observer。
● Observer方法需要一个与事件相关的参数,可以把这个参数封装成一个继承EventArgs。
● Observer方法需要一个被监视对象的参数,通过这个参数可以拿到被监视对象的public属性或字段。
● 被监视对象要声明委托的参数列表与Observer方法一致,并且委托符合"...EventHandler"命名惯例。
● 被监视对象同时需要...EventHandler类型的事件变量。
● 被监视对象需要一个事件触发方法,一旦事件被触发,同时会触发所有注册的Observer方法。
● 被监视对象同时需要一个方法,当满足某种条件就触发事件
□ 代码
1: using System;
2: using System.Collections.Generic;
3: using System.Linq;
4: using System.Text;
5: using System.Threading.Tasks;
6:
7: namespace ConsoleApplication14
8: {
9: class Program
10: {
11: static void Main(string[] args)
12: {
13: SmartCar car = new SmartCar();
14: Alarm alarm = new Alarm();
15:
16: car.DetectDistance += alarm.MakeAlert;
17: car.DetectDistance += Display.ShowMsg;
18:
19: car.KeepSafety();
20: Console.ReadKey();
21: }
22: }
23:
24: public class SmartCar
25: {
26: private int distance;//测量与后方车的举例
27: public string brand = "福特";
28: public string type = "翼虎";
29:
30: public delegate void DetectDistanceEventHandler(Object sender, DetectDistanceEventArgs e);//声明委托
31: public event DetectDistanceEventHandler DetectDistance; //声明委托类型的事件
32:
33: //事件一旦被触发就调用所有的注册方法
34: //设计成虚方法以便让子类来继承,这样子类就可以不被观察者监视
35: protected virtual void OnDetectDistance(DetectDistanceEventArgs e)
36: {
37: if (DetectDistance != null)
38: {
39: DetectDistance(this, e);
40: }
41: }
42:
43: //当侦测到与后方车的距离小于50米就触发事件
44: public void KeepSafety()
45: {
46: for (int i = 100; i > 48; i--)
47: {
48: distance = i;
49: if (distance < 50)
50: {
51: DetectDistanceEventArgs e = new DetectDistanceEventArgs(distance);
52: OnDetectDistance(e);
53: }
54: }
55: }
56: }
57:
58: //观察者事件参数
59: public class DetectDistanceEventArgs : EventArgs
60: {
61: public readonly int distance;
62:
63: public DetectDistanceEventArgs(int distance)
64: {
65: this.distance = distance;
66: }
67: }
68:
69: //声音警报
70: public class Alarm
71: {
72: public void MakeAlert(Object sender, DetectDistanceEventArgs e)
73: {
74: SmartCar car = (SmartCar)sender;
75: Console.WriteLine("嘀嘀嘀:与前方车距离是{0},请保持车距",e.distance);
76: Console.WriteLine("前方车品牌为{0},车型为{1}",car.brand, car.type);
77: Console.WriteLine();
78: }
79: }
80:
81: //仪表盘显示
82: public class Display
83: {
84: public static void ShowMsg(Object sender, DetectDistanceEventArgs e)
85: {
86: SmartCar car = (SmartCar)sender;
87: Console.WriteLine("请注意:与前方车距离是{0},请保持车距", e.distance);
88: Console.WriteLine("前方车品牌为{0},车型为{1}", car.brand, car.type);
89: Console.WriteLine();
90: }
91: }
92: }
93:
□ 结果
□ 总结
● Observer方法需要一个与事件相关的参数,可以把这个参数封装成一个继承EventArgs。
● Observer方法需要一个被监视对象的参数,通过这个参数可以拿到被监视对象的public属性或字段。
public void MakeAlert(Object sender, DetectDistanceEventArgs e)
● 被监视对象要声明委托的参数列表与Observer方法一致,并且委托符合"...EventHandler"命名惯例。
public delegate void DetectDistanceEventHandler(Object sender, DetectDistanceEventArgs e);//声明委托
● 被监视对象同时需要...EventHandler类型的事件变量。
public event DetectDistanceEventHandler DetectDistance; //声明委托类型的事件
● 被监视对象需要一个事件触发方法,一旦事件被触发,同时会触发所有注册的Observer方法。
1: //事件一旦被触发就调用所有的注册方法
2: //设计成虚方法以便让子类来继承,这样子类就可以不被观察者监视
3: protected virtual void OnDetectDistance(DetectDistanceEventArgs e)
4: {
5: if (DetectDistance != null)
6: {
7: DetectDistance(this, e);
8: }
9: }
● 被监视对象同时需要一个方法,当满足某种条件就触发事件
1: //当侦测到与后方车的距离小于50米就触发事件
2: public void KeepSafety()
3: {
4: for (int i = 100; i > 48; i--)
5: {
6: distance = i;
7: if (distance < 50)
8: {
9: DetectDistanceEventArgs e = new DetectDistanceEventArgs(distance);
10: OnDetectDistance(e);
11: }
12: }
13: }
参考资料:
※ 《.NET之美》--张子阳,感谢!