背景:
前面在讲观察者模式的时候,讲到了观察者模式的不足,那就是如果如果通知者和观察者之间根本就是互相不知道,那么这样就会导致有时有的观察者是通知不到的,那么怎么办呢?要是能有客户端来决定通知谁,是很好的办法,于是提出了委托。
那么什么是委托呢?什么又是事件呢?
Ø 委托和事件定义
委托:委托是对函数的封装,可以当做给方法的特征指定一个名称。
事件:事件则是委托的一种特殊形式,当发生有意义的事情时,事件对象处理通知过程。
u 那么怎么去理解呢?
比如有两个类,Cat类和Mouse类,在Main函数执行,当Cat的Shout方法触发时,Mouse就执行Run方法。那么这里便抛出一个疑问,那就是如何让Shout触发时,通知老鼠呢,显然猫和老鼠不会认识,也不会主动通知。换言之,在Cat类中,是不会存在关联Mouse类的。此时委托事件便可以解决。
那么怎么去具体理解呢?
我们知道委托是一种引用方法的类型。一旦为委托分配了方法,委托将与该方法具有完全相同的行为。而事件则是在发生其他类或对象关注的事情时,类或者对象可以通过事件通知它们。
那么老鼠和猫的委托事件怎么实现呢?
我自己是这样理解的:
当猫发出“喵”的一声时,此时声音便是与猫具有相同行为的实体,那么声音随着介质传到老鼠的耳朵里,这样便使得老鼠更新自己的行为,逃跑。这里的声音便是委托,因为它具有猫的功效,可以引起注意。而声音随着介质传到老鼠的耳朵里,引起老鼠的逃跑这是事件。此外如果猫没有发出声音,悄无声息地站在老鼠的面前,这也会引起老鼠的逃跑行为,那么可见这里老鼠把通知委托给了猫,猫的行为引起了老鼠的逃跑事件。可见此时老鼠把自己的行为更新给了猫,一旦猫有什么行为,猫会跟着做出相应的反应。
再比如我们平时都在机房学习,有的同学可能喜欢看看网页或者电视剧什么的,但是又害怕被老师知道,因为在机房学习期间是不被允许的,所以他们是保持警惕的,有的人让门口的人记得通知自己一下,但是可能门口的人一下子没有反应过来,没有办法通知,这时老师可能会咳嗽或者站到你面前等等,来通知你,促使你更新自己的行为,比如关闭视频或者网页。
u 程序举例
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication3
{
class Cat
{
private string name;
public Cat(string name)
{
this.name = name;
}
public delegate void CatShoutEventHandler(); //声明委托
public event CatShoutEventHandler CatShout; //声明事件CatShout,他的事件类型是委托CatShoutEventHandler
public void Shout()
{
Console.WriteLine("喵,我是{0}.", name);
if (CatShout != null)
{
CatShout(); //表明当执行shout()方法时,如果Catshout中有对象登记事件,则执行catshout()
}
}
}
class Mouse
{
private string name;
public Mouse(string name)
{
this.name = name;
}
public void Run()
{
Console.WriteLine("老猫来了,{0}快跑!", name); //{0}表示参数,0表示是第一个参数
}
}
}
客户端代码
static void Main(string[] args) //程序的入口点
{
Cat cat = new Cat("Tom");
Mouse mouse1 = new Mouse("Jerry");
Mouse mouse2 = new Mouse("Jack");
cat.CatShout += new Cat.CatShoutEventHandler(mouse1.Run);
cat.CatShout += new Cat.CatShoutEventHandler(mouse2.Run);
cat.Shout();
Console.Read();
}
u 注意
一、
委托对象用关键字delegate来声明,如上例:public delegate void CatShoutEventHandler();
事件对象用event关键字声明,如上例:public event CatShoutEventHandler CatShout;
二、
一个委托可以搭载多个方法,所有方法被一次唤起,再者委托可以使得委托对象所搭载的方法并不需要属于同一个类。
委托对象所搭载的所有方法必须具有相同的原形和形式,也就是拥有相同的参数列表和返回值类型。