形式上看,事件是一种特殊的委托,委托就像我们的int啊,string啊一样,是一种类型,只不过int类型的变量指向的是一个整数的地址,string类型的变量,指向的是一个字符串的地址,而委托类型的变量,指向的是一个方法的地址。
委托采用event关键字修饰以后,类外部就无法直接调用这个委托,外部只能给委托上绑定方法或者移除方法。委托的调用完全由类内部自己确定。
用winform里面常见的键盘按下来简单说明下事件,人家觉得键盘按下时很重要,我们肯定希望在键盘时调用一个什么方法,但是人家又不知道我们究竟会调用一个什么样的方法,人家就公开一个事件给我们,我们只需要将我们想要调用的方法绑定在人家公开的事件上即可。而我们又想知道,究竟是哪个控件对象触发了键盘按下事件?所以人家公开的事件就提供了一个object类型的参数。当事件触发时,人家就把触发事件的那个控件对象给我们传了进来。还有一些剩下的我们也想知道的事情,比如我们按下的是哪个键(我们自然不会不知道我们按下的是哪个键,但是通过这样的处理,我们可以把所有的有关键盘按下的处理逻辑都放在这个事件里,通过读取人家返回给我们的按键进行不同逻辑,比如按下A弹窗"你好",按下B弹窗"再见"什么的)?人家就把很多其他的东西,作为第二个参数传给我们???EventArgs(具体忘记了键盘按下第二个参数的类型)
不使用event关键字修饰委托类型的变量,那就是普通的委托,从功能角度来说,和使用事件没太大区别,但是这样,外界就可以随便调用你的委托,这就不叫事件了,事件事件,顾名思义,要有触发条件的,触发条件自然是它所在的类决定的,你随随便便自己就调用了鼠标点击事件,那还叫鼠标点击事件么?
事件的这种机制,刚好也是面向对象开放封闭原则的体现。
在做游戏开发时,事件的采用更为频繁,此时,一般都会有一个全局的事件管理类,比如EventManager,这个类有一个添加监听的方法AddListener,还有个触发事件的方法Raise。通过不同的EventArgs的子类来区分不同模块的事件。比如场上有5个士兵,上来着5个士兵都注册一个挨打的监听,绑定的方法里面会有一个参数,比如BattleEventArgs,BattleEventArgs里面有一个字段表示士兵ID,还有个参数表示攻击力,这个方法的最外层会判断传入的ID是不是和自己ID匹配,匹配则根据攻击力和自己防御力扣除自己血量
当A士兵打了C士兵。A士兵就会调用EventManager的Raise方法,把一个BattleEventArgs的对象传进去,ID就是C士兵ID,攻击力就是自己的攻击力,此时5个士兵都会触发自己添加的挨打监听,但是只有C士兵ID匹配,所以C士兵会掉血。
这样,A士兵无需获得C士兵的引用,就可以达到目的,降低了耦合,而且层次上更加鲜明(通过不同的EventArgs子类来实现不同模块的分离) |