上一篇文章介绍了观察者模式如何降低观察者和目标之间的耦合,并通过一个实例具体实现了观察者模式,本篇文章从上篇文章的实例继续,介绍中介者模式是如何带来对象间进一步的松耦合。
文章目录
问题提出
上篇文章用一个实例介绍了观察者模式,具体就是场景中有多个敌人,有一个UI文本显示场景中的剩余敌人数,还有一个大门,当敌人被消灭完后打开。那么当敌人死亡时,就需要发布通知,而UI文本和大门就会收到消息执行相关流程。
我们通过观察者模式实现了敌人并不需要知道订阅者的信息,只需要简单地发布通知即可,具体对订阅者进行通知是通过抽象的目标。下面分析下还存在什么问题,看下面大门的蓝图,可以看到大门还是需要获取敌人对象数组,以设置敌人数量和绑定接收通知的事件。同样UI中也需要相同的操作,这样带来的问题一个是,订阅者依赖发布者的信息造成耦合,另一个是每有一个新的订阅者都需要先获取到所有敌人,但其实想一想这个信息是共享的,要是能只获取到一次就完美了。
这时引出中介者模式(Mediator Pattern)解决这些问题。
概述
中介者模式也是一种行为型模式,用一个中介对象封装一系列的对象交互,中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。
中介者模式包含如下角色:
- Mediator: 抽象中介者
- ConcreteMediator: 具体中介者
- Colleague: 抽象同事类
- ConcreteColleague: 具体同事类
可以看到两个同事之间没有依赖关系,都是通过中介者进行通信。更具象的一个例子是聊天室,如果不使用中介者模式,可以想象到有多少条依赖关系,而关系越多,每次修改逻辑需要修改的代码就会越多,也越不适宜代码的复用,而通过引入中介者,所有人发的消息只需发送给中介者,中介者再进行转发,那么每个聊天的对象只需要和中介者建立依赖关系即可。
问题解决
回到第一部分的问题上来,我们通过中介者模式来进一步减少对象间的依赖关系。
这里我们在新建 BP_GameState
作为中介者,给其添加OnEnemyKilled
两个事件分发器。
在敌人蓝图中,销毁时调用 BP_GameState
的 OnEnemyKilled
事件分发器
那么在UI和大门中就不需要循环每个敌人来绑定事件,而是通过 BP_GameState
这个中介者来绑定
现在还有个问题就是我们在UI和大门中还是需要获取到所有敌人来设置初始的敌人数,这也不适合当敌人数量会动态增加时的场景。
我们再在 BP_GameState
中增加一个 OnEnemySpawn
事件分发器,在敌人BeginPlay
中调用这个事件分发器。
之后在UI和大门中绑定事件,实现敌人数量的增加即可
一个优化就是通过新增一个接口,让BP_GameState
来实现接口中的KillEnemy
和EnemySpawn
函数,这样我们在每个敌人对象中就不需要转换为BP_GameState
了,这样就算我们以后用了其他的GameState
类,下面的代码仍能够复用。
总结
优点
中介者模式的优点:
- 简化了对象之间的交互。
- 将各同事解耦。
- 减少子类生成。
- 可以简化各同事类的设计和实现。
缺点
中介者模式的缺点
- 在具体中介者类中包含了同事之间的交互细节,可能会导致具体中介者类非常复杂(臃肿的控制器),使得系统难以维护。
模式应用
MVC架构中控制器,Controller 作为一种中介者,它负责控制视图对象View和模型对象Model之间的交互。当然别忘了这可能会造成Controller特别臃肿。
参考资料
Game Design Pattern ------ 中介者模式
【双字精译】虚幻引擎中的设计模式:中介者模式------Ali Elizoheiry|游戏开发游戏编程模式游戏设计模式虚幻蓝图编程事件管理器教程UnrealUE4UE5