Quel modèle est-ce, et dois-je le faire?

9

Je fais un jeu en as3 en utilisant flash develop et flash cs5. Tout est orienté objet. Je me demandais, si je devais avoir une classe "passerelle" qui a une référence de propriété à toutes les instanciations des autres classes, et je passe juste cette classe passerelle à de nouveaux objets, afin qu'ils aient accès à chaque classe. Ainsi:

 var block:Block = new Block(gateway);

 //In the block class:
 this.gateway.player.setHealth(100);
 //Or:
 this.gateway.input.lock();

Est-ce comme un motif singleton ou quelque chose? Dois-je faire ça?

Tetrad
la source

Réponses:

13

C'est ce qu'on appelle le modèle de conception d'objet de contexte , et c'est mieux que le modèle singleton.

  • Les objets contextuels facilitent les tests, car vous pouvez transmettre des contextes fictifs aux fonctions que vous souhaitez tester. Les singletons l'entravent, car pour se moquer des singletons, vous devez les faire non pas des singletons.
  • Les objets de contexte rendent votre "état global" explicite, et donc plus facile à raisonner. Si une fonction ne prend pas d'objet contextuel, vous savez qu'elle n'utilise aucun état de contexte global. Vous n'avez aucune garantie de ce type avec des singletons ou des variables globales.
  • Les objets contextuels sont très légèrement plus lents si vous ne les utilisez pas, car vous ajoutez un autre paramètre à tous vos appels de fonction. Ils peuvent être plus rapides que les globaux si vous les utilisez et sont presque toujours plus rapides que les singletons.
  • Les objets contextuels sont plus faciles à implémenter; ils vivent généralement sur le tas ou la pile d'une manière normale. Les singletons ont des problèmes délicats impliquant le filetage dans de nombreuses langues.

Donc non, ce n'est pas un singleton, c'est bien mieux qu'un singleton.

Cependant, vous passez toujours un crapload d'état - le fait que vous gardiez tout cela dans une seule variable locale le rend plus explicite, mais crée toujours une confusion majeure de préoccupations . Gardez à l'esprit la règle de la responsabilité unique . Il est logique qu'il y ait un contexte qui possède le lecteur et le niveau actuel - ils sont liés - mais pourquoi le même contexte possède-t-il votre entrée de clavier?

Considérez différents niveaux de contextes, par exemple:

  • GameplayContext - possède le joueur, les ennemis, la géométrie du niveau, etc.
  • InputContext - possède des poignées de clavier et de souris, des événements d'entrée, etc.
  • GraphicsContext - possède les textures, la poignée de la fenêtre, etc.
  • GlobalContext - possède un GameplayContext, un GraphicsContext et un InputContext. C'est là que vous souhaitez appliquer le modèle de localisateur de service , pour pouvoir échanger certains contextes pour d'autres selon vos besoins. Et peut-être, pour une itération et des tests rapides, cela devrait être dans une vraie variable globale - sachez simplement que chaque fois que vous l'utilisez, vous accumulez de la dette technologique .

Ces contextes confondent encore quelque peu les préoccupations - peut-être qu'un gestionnaire d'événements prend un GameplayContext et n'a vraiment besoin que du joueur - mais les responsabilités sont clairement définies. Vous savez que quelque chose qui prend un GameplayContext ne chargera pas une texture; quelque chose qui prend un InputContext ne peut pas tuer un joueur.

Communauté
la source
+1 Bonne réponse. Cependant, certains des problèmes de vitesse ou de thread ne s'appliquent pas vraiment dans ce contexte (ActionScript3 ne prend pas en charge le thread et de nombreux mécanismes d'amélioration de la vitesse qui fonctionnent en C ++ ne s'appliquent pas lors de l'utilisation d'AS3).
bummzack
Je ne sais pas grand-chose sur l'AS3VM, mais dans la plupart des langages dynamiques, le coût de passage / réception / utilisation d'un local est toujours plus rapide (recherche de tableau) que le coût de recherche d'un global (recherche de hachage), et beaucoup plus rapide que appeler une fonction (craploads de trucs) pour y accéder. Je pense donc que les conseils s'appliquent toujours.
0

Cela ne ressemble pas au motif Singleton. D'après ce que je comprends, vous passez un objet avec des références à des objets de jeu importants à toutes vos instances.

Si tel était le modèle Singleton, vous auriez:

AudioManager.getInstance().playSound(XY);

Alors que dans votre cas, vous pourriez avoir:

this.gateway.getAudioManager().playSound(XY);

Il semble fondamentalement le même, mais ce n'est vraiment pas le cas. Si vous souhaitez remplacer AudioManagerpar une nouvelle (classe étendue) comme ExtendedAudioManager, vous heurteriez un mur en utilisant le motif Singleton. Votre approche de passerelle s'en occupera très bien cependant.

L'inconvénient de votre approche est que vous devrez faire le tour du gatewaymonde. Le modèle de localisateur de service (proposé par Joe Wreschnig dans ce fil), ressemble à un bon remplacement pour votre "modèle de passerelle".

Parfois, il est préférable de simplement exécuter la méthode simple et directe au lieu de trop concevoir les choses. Surtout quand c'est un petit projet ou un prototype. Peut-être que vous pourriez faire gatewayune sorte de variable globale .. par exemple. Game.gatewayet courir avec.

bummzack
la source
-2

La plupart des solutions à ce problème, y compris le modèle Singleton, impliquent l'utilisation de variables statiques. Si vous n'avez qu'un seul joueur, vous pouvez simplement faire en sorte que Player soit une classe singleton, ce qui signifie que vous pouvez accéder à l'instance Player via quelque chose comme Player.currentPlayer. Cependant, beaucoup de gens font rage contre les Singletons. Vous pouvez également avoir un ResourceManager ou une classe similaire qui contient des références statiques à diverses variables globales utiles ou plutôt darn-global. Dans votre code, vous pouvez tout aussi bien rendre les variables "Gateway" statiquement accessibles au lieu de gonfler votre code en le faisant circuler partout.

Gregory Avery-Weir
la source
La question a considérablement changé depuis que j'ai fait cette réponse, suffisamment pour que cela ne semble pas valoir la peine de la modifier.
Gregory Avery-Weir
2
Hormis le titre, rien n'a changé dans la question.
bummzack
1
Quelle? Rien n'a changé autre que le titre. -1
AttackingHobo
Je pense que je pensais au titre ici; Je me souviens que le titre d'origine était quelque chose comme "Comment dois-je faire cela?" Il est tout à fait possible que j'aie mal lu le titre / la question initiale lorsque j'ai fait la réponse.
Gregory Avery-Weir