一、概述
委托首先是一个方法指针。
委托也是一个类,当对其进行实例化的时候,要将引用方法作为它的构造方法的参数。
事件是为委托施加保护的,它封装了委托类型的变量,使得在类的内部,不管你声明它是public还是protected,它总是private的。在类的外部,注册“+=”和注销“-=”的访问限定符与你在声明事件时使用的访问符相同。
二、委托和事件的使用及Observer设计模式:
Observer设计模式:Observer设计模式是为了定义对象间的一种一对多的依赖关系,以便于当一个对象的状态改变时,其他依赖于它的对象会被自动告知并更新。Observer模式是一种松耦合的设计模式。
我们用Observer设计模式实现高档的热水器烧水过程,给它通上电,当水温超过95度的时候:
1、扬声器会开始发出语音,告诉你水的温度;
2、液晶屏也会改变水温的显示,来提示水已经快烧开了,同时显示热水器厂家名称。
现在我们需要写个程序来模拟这个烧水的过程,我们将定义一个类来代表热水器,我们管它叫:WaterHeater,它有代表水温的字段,叫做temperature;当然,还有必不可少的给水加热方法heatUp()。一个发出语音警报的类Alarm和一个显示类Screen,他们继承Observer抽象类。
首先我们需要一个热水器类:
public delegate void ActionEventHandler(object sender, ConcernEventArgs e); public class WaterHeater { public event ActionEventHandler action; private string manufacturer ; public string Manufacturer { get { return manufacturer; } private set { manufacturer = value; } } public WaterHeater(string manufacturer) { this.manufacturer = manufacturer; } public void attach(Observer observer) { action += observer.display; } public void detach(Observer observer) { action -= observer.display; } public static WaterHeater getInstance(string manufacturer) { return new WaterHeater(manufacturer); } public void heatUp() { for (int i = 0; i <= 100; i++) { if (i > 95) { ConcernEventArgs e = new ConcernEventArgs(i,this.manufacturer); action.DynamicInvoke(this, e); } } } }
然后是一个标准的事件模型:
事件模型规范:
1. 委托类型名称以EventHandler结束;
2. 原型返回值为void;
3. 事件原型具有两个参数:sender表示事件触发者,e表示事件参数;
4. 事件参数名称要以EventArgs结束;
public class ConcernEventArgs : EventArgs { internal readonly int temprature; internal readonly string manufactor; public ConcernEventArgs(int temprature, string manufactor) { this.temprature = temprature; this.manufactor = manufactor; } }
此时我的热水器类就完成了。
我们还需要一个观察者Observer抽象类
public abstract class Observer { public abstract void display(object sender, ConcernEventArgs e); }
实现Alarm类继承Observer抽象类重写display方法:
public class Alarm:Observer { public static Alarm getInstance() { return new Alarm(); } public override void display(object sender, ConcernEventArgs e) { Console.WriteLine("Alarm:" + e.manufactor); Console.WriteLine("Alarm:"+e.temprature ); } }
实现Screen类继承Observer抽象类重写display方法:
public class Screen : Observer { public static Screen getInstance() { return new Screen(); } public override void display(object sender, ConcernEventArgs e) { Console.WriteLine("Screen:" + e.manufactor); Console.WriteLine("Screen:" + e.temprature); } }
下面我们用控制台程序实现热水器烧水过程:
class Program { static void Main(string[] args) { Alarm alarm = Alarm.getInstance(); Screen screen = Screen.getInstance(); WaterHeater waterHeater = WaterHeater.getInstance("BOB"); waterHeater.attach(alarm); waterHeater.attach(screen); waterHeater.heatUp(); Console.ReadKey(); } }
Observer设计模式中主要包括如下两类对象:
Subject:主题对象,它往往包含着其他对象所感兴趣的内容。在本范例中,热水器就是一个监视对象,它包含的其他对象所感兴趣的内容,就是temprature字段,当这个字段的值快到100时,会不断把数据发给监视它的对象。
Observer:监视者,它监视Subject,当Subject中的某件事发生的时候,会告知Observer,而Observer则会采取相应的行动。在本范例中,Observer有警报器和显示器,它们采取的行动分别是发出警报和显示水温。
在本例中,事情发生的顺序应该是这样的:
1.警报器和显示器告诉热水器,它对它的温度比较感兴趣(注册)。
2.热水器知道后保留对警报器和显示器的引用。
3.热水器进行烧水这一动作,当水温超过95度时,通过对警报器和显示器的引用,自动调用警报器的display()方法、显示器的display()方法。