详解事件和委托

来源:互联网 发布:衣柜合理布局 知乎 编辑:程序博客网 时间:2024/06/05 19:02

委托

委托实质上是一个类,是对方法/函数的封装,是一种引用方法的类型,可以当作给方法的特定特征指定一个名称。委托内部有三个重要成员:目标,方法,前一个委托。一旦为委托分配了方法,委托将与该方法具有完全相同的行为。委托对象使用关键字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();使用它就等于减少一个需要触发事件时通过的对象。

1 0
原创粉丝点击