Comment éviter le modèle singleton pour le planificateur d'événements?


13

Je veux créer un planificateur d'événement pour mon jeu, je veux essentiellement pouvoir planifier le déclenchement d'un événement de jeu. Il peut s'agir d'un déclencheur unique ou périodique (événement déclencheur "E_BIG_EXPLOSION" sur 5 secondes ...).

Il est tentant de penser que cela peut être un bon endroit pour utiliser un Singleton, mais les singletons peuvent être assez mauvais et ils ont tendance à se propager comme une maladie ... alors j'essaie de les éviter à tout prix.

Quelle conception proposeriez-vous pour éviter l'utilisation de singleton dans ce cas?


Voir cette réponse sur les suppléants aux singletons
BlueRaja - Danny Pflughoeft

Réponses:


12

Vous devriez avoir un ensemble d'interfaces très bien défini qui sont autorisées à transmettre ou recevoir des messages - leur donner une référence à un EventScheduler devrait être trivial. Si ce n'est pas le cas, ou si vous pensez que cela impliquerait de passer le planificateur d'événements à «trop» de types distincts, alors vous pourriez avoir un problème de conception plus important entre vos mains (une dépendance promiscueuse, que les singletons ont tendance à exacerber, pas à résoudre). ).

N'oubliez pas que, bien que la technique de transmission du planificateur aux interfaces qui en ont besoin soit une forme d '« injection de dépendance », vous n'injectez pas dans ce cas une nouvelle dépendance. Il s'agit d'une dépendance que vous avez déjà dans le système, mais vous en faites maintenant une dépendance explicite (par rapport à la dépendance implicite d'un singleton). En règle générale, les dépendances explicites sont plus préférables car elles sont plus auto-documentées.

Vous vous offrez également plus de flexibilité en découplant les consommateurs de la planification des événements les uns des autres (car ils ne sont pas tous nécessairement liés au même planificateur), ce qui peut être utile pour tester ou simuler les configurations client / serveur locales ou un certain nombre d'autres options. - vous n'avez peut-être pas besoin de ces autres options, mais vous n'avez pas déployé d'efforts pour vous en limiter artificiellement, ce qui est un plus.

EDIT: Tout ce que je veux dire quand je parle de passer le planificateur est le suivant: si vous avez un composant de jeu qui est responsable de la réponse à la collision, il est probablement créé via une usine de répondeurs de collision qui fait partie de votre couche physique. Si vous construisez la fabrique avec une instance de planificateur, elle peut ensuite transmettre cette instance à tous les répondeurs qu'elle crée, qui peuvent ensuite l'utiliser pour déclencher des événements (ou peut-être s'abonner à d'autres événements).

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;
}

C'est évidemment un exemple terriblement artificiel et simplifié car je ne sais pas quel est votre modèle d'objet de jeu; il illustre cependant rendre explicite la dépendance à l'égard du planificateur d'événements et montre un certain potentiel d'encapsulation supplémentaire (vous n'auriez pas nécessairement besoin de transmettre aux répondeurs le planificateur s'ils communiquaient avec un système de réponse aux collisions de niveau supérieur au même niveau conceptuel que le usine qui a traité les problèmes liés à la génération d'événements via le planificateur. Cela isolerait chaque implémentation individuelle du répondeur des détails de mise en œuvre du système de répartition des événements, tels que l'événement spécifique à déclencher lors d'une collision, ce qui peut être idéal pour votre système - - ou pas).


Merci pour votre réponse, j'ai pensé à l'injection de dépendance. Ce serait très bien si vous pouviez préciser un peu mieux votre solution? (Pseudo-code? Diagramme?). Je pense que je suis votre idée, mais c'est peut-être juste ma propre interprétation du concept.
Mr.Gando

Il est difficile de le faire d'une manière utile sans savoir quelles classes de vous envoient / reçoivent des événements au planificateur.

Dans mon moteur, n'importe quelle entité de jeu peut avoir un composant "Event Dispatcher" attaché ...
Mr.Gando

7

Un répartiteur d'événements est l'un de ces cas où un singleton n'est pas la pire idée du monde, mais je vous félicite d'avoir essayé de l'éviter. Vous trouverez peut-être quelques idées ici .


1
Merci !, chaque fois qu'un singleton est créé un chaton meurt;)
Mr.Gando

3

J'ai tendance à éviter les singletons aussi, mais il y a quelques objets qui ont le plus de sens en tant que singletons et un système de messagerie central en fait partie. Malgré les diatribes que j'ai entendues, les singletons sont certainement bien meilleurs que les variables / fonctions globales car vous devez toujours y répondre délibérément (par rapport aux valeurs globales apparaissant comme par magie de nulle part).

En fin de compte, chaque expéditeur et destinataire de message doit avoir un point d'intersection commun, et il est préférable de garder vos objets découplés en ayant un singleton commun partagé par tout plutôt que de faire en sorte que chacun de vos expéditeurs de message connaisse directement les récepteurs de message.

Bien que je sois sûr qu'une autre architecture pourrait être conçue pour votre système d'événements, cela me semble être un gaspillage d'efforts de trop y penser, en particulier lorsque l'utilisation d'un système d'événements est déjà une grande victoire pour ne pas en utiliser un.

EDIT: Quant à votre exemple spécifique d'un événement d'explosion envoyé sur un déclencheur périodique, je ferais probablement en sorte que les événements soient envoyés dans un autre objet (comme le pistolet à tourelle ou quoi que ce soit à l'origine de ces explosions) et non dans le système d'événements central. Cependant, ces événements seraient toujours envoyés au système central des événements.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.