前言
最近在学习Unity游戏设计模式,看到两本比较适合入门的书,一本是unity官方的 《Level up your programming with game programming patterns》 ,另一本是 《游戏编程模式》
这两本书介绍了大部分会使用到的设计模式,因此很值得学习
本专栏暂时先记录一些教程部分,深入阅读后续再更新
文章目录
- 前言
- 使用观察者模式
- 委托和事件
- 发布订阅模式
- 事件总线
【Unity】观察者模式、中介者模式和事件总线
建议看看这个视频,相信你会对代码实现有个明显的了解
使用观察者模式
在游戏运行中发生了各种各样的事件,例如玩家消灭敌人,玩家受伤,或是收集到道具。不同的GameObject之间想要在发生事件后进行某类交互,此时我们需要在事件发生后去通知那些想要交互的对象。
为了避免耦合,我们肯定要避免不同对象间的复杂引用关系。同时要保证事件能够通知到,一种好方法是使用观察者模式:
观察者模式就好比向许多观众发送广播的无线电台,电台本身不需要知道有谁在收听,只需要进行正常的广播即可。而收听了电台的听众们自然就会接受到广播,且不同听众之间不知道其他听众的存在,在他们看来自己与电台是一对一的关系。
我们将正在广播的对象称为Subject主题,将监听的对象称为Observer观察者或订阅者
通过观察模式,可以将主题和观察者解耦,主题发布事件时不需要关心有没有观察者,也不关心他们在收到事件后会干嘛。而观察者虽然与主题耦合,但是与其他观察者之间不相干。
委托和事件
在学习C#的时候,我们学习了委托和事件,其实委托和事件就是一种观察者模式,想象观察者们将自己的方法注册到主题的委托当中,当主题触发委托后就会广播这些事件。
并且使用委托,我们对方法的注册更加灵活,我们可以当GameObject(观察者们)在OnEnable的时候向主题进行事件注册,而在OnDisable的时候向主题取消注册的事件。
发布订阅模式
发布定义模式是观察者模式的升级版:
同样的例子,假设这个电台自身完全不生产任何事件。现在有一个广告商要向电台投放广告,那么电台在接收到广告商投放的广告之后会将广告分发给订阅的观察者们,这些观察者在接到广告后选择如何行动。
此时的主题更像是一个中介,它接受来自Publisher发布者 的消息,并将其分发给订阅了该主题的订阅者。当然发布者也不只有广告商,也会有主播发布事件,或者听众来电发布事件。但是订阅者们并不关心是谁发送了,发布者们也不关心谁会收到,他们只需要完成自己的事情,由主题作为中介进行交互即可。这样观察者和发布者本身没有耦合,却能实现不同组件之间的交互。
我们将此时的主题称为事件频道Event Channel, 我们当然可以定义多个频道,比如有人只订阅体育频道,有人订阅音乐频道,有人两个都订阅了。发布者只需完成发布到他们所订阅的频道即可,而观察者只需接受来自订阅频道的事件。
如果所有的事件全部都塞进了一个事件频道,我们将这种模式称为事件总线Event Bus 模式
事件总线
【Unity教程搬运】事件总线(Event Bus)
事件总线模式其实就是对发布订阅的简单抽象,我们看发布订阅模式其实分为三步:
1.订阅者订阅事件频道
2.发布者向事件频道发布消息
3.订阅者收到事件频道广播的订阅消息(触发订阅事件)
而事件总线模式则将整个步骤抽象成了两步:
1.订阅者向事件总线注册事件
2.发布者直接触发事件总线中的事件列表
也就是说,相比于观察订阅模式,事件总线维护的并不是观察者的列表,而是观察者需要触发的事件本身。那么发布者也不需要让事件频道分发消息了,直接触发对应的事件列表即可。
因此事件总线直接提供了事件的注册方法,事件撤销方法和事件总线的触发方法。通过订阅者本身的事件驱动
所以本质上看事件总线中维护的事件列表其实就是不同的泛型委托吧
好处是我们可以把事件总线设计成一个静态的工具类(注意应用时考虑是否使用单例模式或DDOL)
当然,我们只需对事件总线触发代码进行优化就可以改变全局的事件触发状态,例如我们可能并不想一次性触发所有事件,那么也可以在总线中定义一个命令缓冲区,让所有事件一个一个地触发。(或者将多次触发的同个事件合并只触发一次)