委托
委托实质上是一个类,是对方法/函数的封装,是一种引用方法的类型,可以当作给方法的特定特征指定一个名称。委托内部有三个重要成员:目标,方法,前一个委托。一旦为委托分配了方法,委托将与该方法具有完全相同的行为。委托对象使用关键字delegate来声明。
普通代码里这样调用方法:
aBird.Fly();
封装到委托里,aBird 就是目标,Fly 就是方法。委托可以组成链,“前一个委托”用于支持这种链式结构。
MethodInvoker mi = new MethodInvoker(aBird.Fly);
mi();
这段和上面的 aBird.Fly 是一个效果,但不是直接调用。可以将 mi 传递到其他地方,再进行调用。委托在方法和调用方之间建立了间接性。 事件是基于委托的通信机制。如果一个对象的状态改变了,我们可能希望将这种改变通知给外界。
从实现角度看,“通知”其实就是调用接收方的方法。困境在于,我们不知道谁对这些改变有兴趣,有多少人对这些改变有兴趣,所以,我们无法直接调用方法。
.net中有两个办法解决这个问题,接口和委托。
这两个的含义都是“约定”,目的则是“分离”,换句话说,就是:商量好了,分头行动。接口是对类成员的约定,委托是对参数和返回值的约定。对于简单的通知,接口有些麻烦,委托更好一些,所以,我们将一个委托加到类中,让它保存应该调用的方法。但光秃秃的一个字段有点难看,好像没穿衣服一样。为了让代码更好看,.net 引入了事件的概念。
事件
而事件则是委托的一种特殊形式,在发生其他类或对象关注的事情时,类或对象可通过事件通知它们(事件对象来处理这个通知过程)。
事件本质上是一个方法,事件提供 add, remove,将方法挂到这个委托中,或从此委托中移除。像这样:
//订阅事件
button1.Click += new EventHandler(button1_Click);
//退阅事件
button1.Click -= new EventHandler(button1_Click);
如果A订阅了B的事件,那么它们之间的引用关系是这样:B引用委托,委托引用A。
这就是说,在退阅事件之前,A不会被当作垃圾回收,因为B包含对它的引用。
因此,委托和事件的区别是:委托与类,结构,接口,枚举是一类,而事件属类成员,和属性,方法,字段是一类。
综合实例应用
Class Cat{
private String name;
public Cat(String name){
this.name = name;
}
//声明一个名为CatShoutEventHandler的委托
public delegate void CatShoutEventHandler();
//声明事件CatShout,它的事件类型是委托CatShoutEventHandler
public event CatShoutEventHandler CatShout CatShout;
public void shout(){
System.out.println("I am cat " + name + ".");
//当执行Shout()方法时,如果CatShout中有对象登记事件,则执行CatShout
if(CatShout != null){
CatShout();
}
}
}
该类中的CatShout()是无参数无返回值的方法,因为事件CatShout的类型是委托CatShoutEventHandler,而CatShoutEventHandler就是无参数、无返回值的。
Class Mouse{
private String name;
public Mouse(String name){
this.name = name;
}
public void run(){
System.out.println("Cat is comming ," + name + " run!");
}
}
//测试方法
public static void main(String[] args){
Cat cat = new Cat("Tom");
Mouse JerryMouse = new Mouse("Jerry");
Mouse JackMouse = new Mouse("Jack");
//将Mouse的run()方法通过实例化委托Cat.CatShoutEventHandler登记到Cat事件CatShout当中
cat.CatShout += new CatShoutEventHandler(JerryMouse.run);
cat.CatShout += new CatShoutEventHandler(JackMouse.run);
cat.shout();
}
运行结果:
I am cat tom.
Cat is coming,JerryMouse run!
Cat is coming,JackMouse run!
几点说明:
1、
new CatShoutEventHandler(JerryMouse.run)
的含义是实例化一个委托,而委托的实例其实就是Mouse的run()方法;
2、
cat.CatShout +=
表示
cat.add_CatShout(new CatShoutEventHandler(JerryMouse.run));
“+=”就是增加委托实例对象的意思;”-=”就是移除委托实例对象的意思add_CatShout();使用它就等于减少一个需要触发事件时通过的对象。