就举个C#常用的游戏编程领域的例子吧。假设有个布尔值bool isDead 表示主角是否死亡,造成主角死亡也就是isDead为真的情况有很多,比如主角生命值降低到0或以下、遭到一击必杀的攻击、跌落悬崖等等。一旦主角死亡,将会触发一系列方法,比如播放死亡音效void PlaySfxDead()、弹出游戏结束画面void PopUpGameOver()等。
以上就是需求。你不知道在玩家的一顿神操作之下,主角什么时候会死。
假设游戏每秒跑30帧,一种比较不优雅的做法是每帧或者每隔几帧,又或者每隔一段时间判断一下isDead是不是为真,一旦为真就把相关的方法全部调用一遍。这种做法的缺点是增加了高频率执行的代码,用多了影响性能。
另一种同样不优雅的做法是在所有会导致主角死亡的情况里面,都把死亡要触发的相关方法全部调用一遍。这种做法的缺点是每增加一种让主角死亡的情况,都要记得把全部要触发的方法加上;每增加一种死亡要触发的方法,都要翻出所有让主角死亡的情况,逐条加上新方法,不利于代码维护,一不留神就出bug了。用比较装逼的话来讲叫做代码的耦合性太强。
一旦用上了委托和多播,把主角的死亡先声明成一个事件,再把这个事件要触发的所有方法+=进去,最后把这个事件的广播写进isDead的set里面。于是只要前面提到的任何让isDead为真的情况发生了,这个事件就会广播出去,让全村所有相关的方法都知道主角死了,全自动执行。这种做法的优点是既不会增加高频率执行的代码,又不用管新增的死亡方式要触发什么东西,如果新增了死亡要触发的方法,只需在最开头把这个新方法+=进事件里面就行了。是不是感觉整个人都优雅了起来?