Est-ce une mauvaise conception d'avoir 2 classes qui ont besoin l'une de l'autre?
J'écris un petit jeu dans lequel j'ai une GameEngine
classe qui a quelques GameState
objets. Pour accéder à plusieurs méthodes de rendu, ces GameState
objets doivent également connaître la GameEngine
classe - c'est donc une dépendance circulaire.
Pourriez-vous appeler cette mauvaise conception? Je demande simplement, parce que je ne suis pas tout à fait sûr et à ce moment je suis encore en mesure de refactoriser ces choses.
c++
architecture
shad0w
la source
la source
Réponses:
Ce n'est pas une mauvaise conception par nature, mais cela peut facilement devenir hors de contrôle. En fait, vous utilisez ce design dans vos codes de tous les jours. Par exemple, vector sait que c'est le premier itérateur et les itérateurs ont un pointeur sur leur conteneur.
Maintenant, dans votre cas, il est beaucoup mieux d'avoir deux classes distinctes pour GameEnigne et GameState. Puisque fondamentalement, ces deux-là font des choses différentes, et plus tard, vous pourriez définir de nombreuses classes qui héritent de GameState (comme un GameState pour chaque scène de votre jeu). Et personne ne peut nier leur besoin d'avoir accès les uns aux autres. Fondamentalement, GameEngine exécute des gamestates, il devrait donc avoir un pointeur vers eux. Et GameState utilise des ressources définies dans GameEngine (comme le rendu, le gestionnaire physique, etc.).
Vous ne pouvez pas et ne devez pas combiner ces deux classes l'une avec l'autre car elles font des choses différentes par nature et la combinaison se traduira par une très grande classe que personne n'aime.
Jusqu'à présent, nous savons que nous avons besoin d'une dépendance circulaire dans notre conception. Il existe plusieurs façons de créer cela en toute sécurité:
Pour conclure sa réponse, vous pouvez utiliser l'une de ces trois méthodes, mais vous devez faire attention à ne pas trop utiliser l'une ou l'autre car, comme je l'ai dit, toutes ces conceptions sont vraiment dangereuses et pourraient facilement entraîner un code non maintenable.
la source
C'est un peu une odeur de code , mais on peut partir avec. Si c'est le moyen le plus simple et le plus rapide de mettre votre jeu en place, foncez. Mais gardez cela à l'esprit car il y a de fortes chances que vous deviez le refactoriser à un moment donné.
Le problème avec C ++ est que les dépendances circulaires ne se compileront pas si facilement , il serait donc préférable de s'en débarrasser au lieu de passer du temps à réparer votre compilation.
Voir cette question sur SO pour quelques opinions supplémentaires.
Non, c'est toujours mieux que de tout mettre dans une seule classe.
Ce n'est pas si génial, mais c'est en fait assez proche de la plupart des implémentations que j'ai vues. Habituellement, vous auriez une classe de gestionnaire pour les états de jeu ( méfiez-vous! ), Et une classe de rendu, et il est assez courant que ce soient des singletons. La dépendance circulaire est donc "cachée", mais elle est potentiellement là.
De plus, comme on vous l'a dit dans les commentaires, c'est un peu bizarre que les classes d'état de jeu effectuent une sorte de rendu. Ils doivent simplement contenir des informations d'état et le rendu doit être géré par un moteur de rendu ou par un composant graphique des objets de jeu eux-mêmes.
Maintenant, il pourrait y avoir le design ultime . Je suis curieux de voir si d'autres réponses apportent une bonne idée. Pourtant, vous êtes probablement celui qui peut trouver le meilleur design pour votre jeu.
la source
C'est souvent considéré comme une mauvaise conception d'avoir à avoir 2 classes qui se réfèrent directement l'une à l'autre, oui. En termes pratiques, il peut être plus difficile de suivre le flux de contrôle à travers le code, la propriété des objets et leur durée de vie peuvent être compliquées, cela signifie qu'aucune classe n'est réutilisable sans l'autre, cela pourrait signifier que le flux de contrôle devrait vraiment vivre en dehors des deux de ces classes dans une troisième classe «médiateur», etc.
Cependant, il est très courant que 2 objets se réfèrent l'un à l'autre, et la différence ici est que généralement la relation dans une direction est plus abstraite. Par exemple, dans un système Model-View-Controller, l'objet View peut contenir une référence à l'objet Model, et saura tout à son sujet, pouvant accéder à toutes ses méthodes et propriétés afin que la vue puisse se remplir elle-même avec les données pertinentes. . L'objet Model peut contenir une référence à la vue afin qu'il puisse effectuer la mise à jour de la vue lorsque ses propres données ont changé. Mais plutôt que le modèle ayant une référence de vue - ce qui rendrait le modèle dépendant de la vue - généralement, la vue implémente une interface observable, souvent avec seulement 1
Update()
et le modèle contient une référence à un objet observable, qui peut être une vue. Lorsque le modèle change, il fait appelUpdate()
à tous ses observables et la vue implémenteUpdate()
en rappelant dans le modèle et en récupérant toutes les informations mises à jour. L'avantage ici est que le modèle ne sait rien du tout sur les vues (et pourquoi devrait-il le faire?), Et peut être réutilisé dans d'autres situations, même celles sans vues.Vous avez une situation similaire dans votre jeu. Le GameEngine connaît normalement les GameStates. Mais le GameState n'a pas besoin de tout savoir sur le GameEngine - il a juste besoin d'accéder à certaines méthodes de rendu sur le GameEngine. Cela devrait déclencher une petite alarme dans votre tête qui dit que (a) GameEngine essaie de faire trop de choses dans une classe, et / ou (b) GameState n'a pas besoin de tout le moteur de jeu, juste la partie rendable.
Trois approches pour résoudre ce problème comprennent:
la source
Il est généralement considéré comme une bonne pratique d'avoir une cohésion élevée avec un faible couplage. Voici quelques liens concernant le couplage et la cohésion.
couplage wikipedia
cohésion wikipedia
faible couplage, haute cohésion
stackoverflow sur les meilleures pratiques
Avoir deux classes se référencent, c'est avoir un couplage élevé. Le cadre google guice vise à atteindre une cohésion élevée avec un faible couplage grâce à des moyens d'injection de dépendance. Je vous suggère de lire un peu plus sur le sujet et ensuite de faire votre propre appel en fonction de votre contexte.
la source