J'écris un jeu qui a beaucoup de composants. Beaucoup d'entre eux dépendent les uns des autres. Lors de leur création, j'arrive souvent dans des situations catch-22 comme "constructeur WorldState
nécessite un PathPlanner
, mais le constructeur PathPlanner
nécessite WorldState
."Initialisation de composants avec des interdépendances - anti-modèle possible?
A l'origine, c'était moins un problème, parce que les références à tout ce qui était nécessaire étaient conservées dans GameEngine
, et GameEngine
a été passé à tout. Mais je n'aimais pas cette impression, car nous avions l'impression que nous donnions trop d'accès à différents composants, ce qui rendait plus difficile l'application des limites.
Voici le code problématique:
/// <summary>
/// Constructor to create a new instance of our game.
/// </summary>
public GameEngine()
{
graphics = new GraphicsDeviceManager(this);
Components.Add(new GamerServicesComponent(this));
//Sets dimensions of the game window
graphics.PreferredBackBufferWidth = 800;
graphics.PreferredBackBufferHeight = 600;
graphics.ApplyChanges();
IsMouseVisible = true;
screenManager = new ScreenManager(this);
//Adds ScreenManager as a component, making all of its calls done automatically
Components.Add(screenManager);
// Tell the program to load all files relative to the "Content" directory.
Assets = new CachedContentLoader(this, "Content");
inputReader = new UserInputReader(Constants.DEFAULT_KEY_MAPPING);
collisionRecorder = new CollisionRecorder();
WorldState = new WorldState(new ReadWriteXML(), Constants.CONFIG_URI, this, contactReporter);
worldQueryUtils = new WorldQueryUtils(worldQuery, WorldState.PhysicsWorld);
ContactReporter contactReporter = new ContactReporter(collisionRecorder, worldQuery, worldQueryUtils);
gameObjectManager = new GameObjectManager(WorldState, assets, inputReader, pathPlanner);
worldQuery = new DefaultWorldQueryEngine(collisionRecorder, gameObjectManager.Controllers);
gameObjectManager.WorldQueryEngine = worldQuery;
pathPlanner = new PathPlanner(this, worldQueryUtils, WorldQuery);
gameObjectManager.PathPlanner = pathPlanner;
combatEngine = new CombatEngine(worldQuery, new Random());
}
Voici un extrait de ce qui précède, c'est problématique:
gameObjectManager = new GameObjectManager(WorldState, assets, inputReader, pathPlanner);
worldQuery = new DefaultWorldQueryEngine(collisionRecorder, gameObjectManager.Controllers);
gameObjectManager.WorldQueryEngine = worldQuery;
J'espère que personne ne l'oublie jamais ce paramètre de gameObjectManager.WorldQueryEngine
, ou bien il échouer. Voici le problème: gameObjectManager
a besoin d'un WorldQuery
, et WorldQuery
a besoin d'une propriété de gameObjectManager
. En dehors de ce problème, il s'agit d'un désordre de maintenabilité, car si les constructeurs ne sont pas appelés dans un ordre spécifique, le programme va planter.
Que puis-je faire à ce sujet? Ai-je trouvé un anti-pattern?
Ok, cela fonctionne bien pour l'extrait que j'ai posté, car GameObjectManager n'est pas une dépendance, mais une de ses propriétés. Mais qu'en est-il lorsque deux objets requièrent une instance l'un de l'autre et ne peuvent pas être instanciés sans cela? (Donc, si tout 'GameObjectManager' était requis, et pas seulement' GameObjectManager.Controllers') –
@Rosarch: Ce que vous appelez est appelé une dépendance cyclique. Généralement, ceci est considéré comme une erreur de conception, avec les exceptions notables des structures de données récursives et des objets auxiliaires qui dépendent * seulement * du même objet qui est responsable de leur création et de leur gestion (tel qu'un pool de ressources). Dans d'autres cas, lorsque vous avez une dépendance cyclique, il y a généralement un sous-ensemble de fonctionnalités dans une ou les deux dépendances qui peuvent être refactorisées dans sa propre classe, de sorte qu'au lieu d'avoir deux classes dépendantes l'une de l'autre la troisième (nouvelle) classe. – Aaronaught
Je voudrais également souligner que dans la terminologie de mon jeu, 'GameObject' se réfère à une entité dans le monde, comme un arbre ou le joueur. Cela ne veut pas dire objet au sens de la POO. –