如何避免事件计划程序的单例模式?


13

我想为我的游戏制作一个事件调度程序,我基本上希望能够安排一个游戏事件的触发时间。这可以是一次触发,也可以是周期性触发(触发事件“ E_BIG_EXPLOSION”每5秒钟触发一次...)。

诱人的是,这可能是使用Singleton的好地方,但是Singleton可能非常邪恶,它们容易像疾病一样传播……所以我不惜一切代价避免使用它们。

在这种情况下,您建议采用哪种设计避免单例使用?


在单例替代者上查看此答案
BlueRaja-Danny Pflughoeft

Answers:


12

您应该有一组定义明确的接口,允许它们传输或接收消息-为它们提供对EventScheduler的引用应该很简单。如果不是这样,或者如果您感觉那样涉及将事件调度程序传递给“太多”的不同类型,那么您可能会遇到更大的设计问题(混杂的依赖性,单身人士会加剧这种情况,而不是解决) )。

请记住,尽管将调度程序传递给需要的接口的技术是“ 依赖注入 ”的一种形式,但是在这种情况下,您并不是要注入新的依赖。这是系统中已经存在的依赖关系,但是现在您将其设为显式依赖关系(与单例的隐式依赖关系相比)。根据经验,显式依赖项更可取,因为它们更易于记录。

您还可以通过将事件调度的使用者彼此分离(因为它们不一定都绑定到同一调度程序)来提供更大的灵活性,这对于测试或模拟本地客户端/服务器设置或许多其他选项很有用-您可能不需要这些其他选项,但是您没有花费任何精力来人为地限制自己使用它们,这是一个优点。

编辑:当我谈论传递调度程序时,我的意思是:如果您有负责响应碰撞的游戏组件,则可能是通过某些碰撞响应器工厂创建的,该工厂是物理层的一部分。如果使用调度程序实例构造工厂,则工厂可以将该实例传递给它创建的任何响应者,然后可以利用它引发事件(或订阅其他事件)。

class CollisionResponderFactory {
  public CollisionResponderFactory (EventScheduler scheduler) {
     this.scheduler = scheduler;
  }

  CollisionResponder CreateResponder() {
    return new CollisionResponder(scheduler);
  }

  EventScheduler scheduler;
}

class CollisionResponder {
  public CollisionResponder (EventScheduler scheduler) {
    this.scheduler = scheduler;
  }

  public void OnCollision(GameObject a, GameObject b) {
    if(a.IsBullet) {
      scheduler.RaiseEvent(E_BIG_EXPLOSION);
    }
  }

  EventScheduler scheduler;
}

这显然是一个非常人为和简化的示例,因为我不知道您的游戏对象模型是什么。但是,它确实说明了对事件调度程序的依赖关系的显式表示,并显示了进一步封装的潜力(如果响应程序以与概念相同的概念级别与更高级别的冲突响应系统进行通信,则不必将响应程序传递给响应程序。通过调度程序处理引发事件的细节的工厂,这会将每个单独的响应程序实现与事件分发系统的实现详细信息隔离开来,例如在碰撞时引发哪个特定事件,这可能是您的系统的理想选择- - 或不)。


感谢您的回答,我想到了依赖注入。如果您可以指定更好的解决方案,那将是非常不错的选择?(伪代码?图?)。我想我遵循您的想法,但这也许只是我对这个概念的解释。
甘多先生2011年

在不知道您的类向调度程序发送/接收事件的情况下,以一种有用的方式很难做到这一点。

在我的引擎中,任何游戏实体都可以连接“事件调度程序”组件...
Mr.Gando 2011年

7

事件分派器是其中单例并不是世界上最坏的主意的情况之一,但是我为避免这种情况而称赞。您可能会在这里找到一些想法。


1
谢谢!每次创建一个单身小猫都会死;)
甘多先生2011年

3

我也倾向于避免单例,但是有一些对象最有意义,因为单例和中央消息传递系统就是其中之一。尽管我听到过很多抱怨,但单例确实比全局变量/函数要好得多,因为您总是必须刻意解决它(而全局值只是凭空魔术般地出现了)。

最后,每个消息发送者和接收者都必须有一个公共的交点,并且最好让所有事物共享一个公共的单例来使对象分离,而不是让每个消息发送者直接了解消息接收者。

虽然我确定可以为您的事件系统设计其他一些体系结构,但对我来说,似乎过于浪费精力了,尤其是在使用事件系统已成为不使用事件系统的重大胜利时。

编辑:至于您在定期触发器上调度的爆炸事件的特定示例,我可能会将事件调度在其他一些对象(例如转塔炮或引起这些爆炸的物体)上,而不是在中央事件系统中调度。但是,这些事件仍将分派中央事件系统。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.