Je construis une IA pour un jeu RTS. (Pour le Spring RTS engine, si quelqu'un est intéressé.) La façon dont je l'ai mis en place consiste principalement en une collection de composants qui communiquent au moyen d'événements déclenchés. Chaque composant a une méthode handleEvent (Event) qui reçoit les événements déclenchés par les autres composants.Surcharge d'une méthode d'une superclasse
L'événement est une interface. Une hiérarchie existe, chaque sous-classe fournissant des informations plus détaillées sur l'événement qu'ils représentent, auquel il est possible d'accéder en utilisant les méthodes getter spécifiques à cette classe. A titre d'exemple, la classe UnitGainedEvent implémente l'interface Event. Cette classe a une sous-classe UnitFinishedEvent (qui indique que la construction d'une unité ou d'un bâtiment est terminée, pour quiconque est curieux.)
Tous les composants ne seront pas intéressés par tous les événements, donc je voudrais laisser les composants choisir simplement les événements ils sont intéressés et ne reçoivent que ceux-là. En outre, l'ensemble des événements possibles est extensible, ce n'est donc pas une option valide pour laisser les composants ont des méthodes désignées pour chaque type d'événement. Au départ, je pensais que le modèle de visiteur pourrait m'aider avec ce problème, mais il échoue car il nécessite également un ensemble fixe de types d'événements. (Je ne suis pas sûr à 100% que je comprends correctement le modèle Corrigez-moi si je me trompe.)
Jusqu'à présent, la seule solution que j'ai trouvée est d'implémenter la méthode handleEvent (Event) de chaque composant quelque chose comme :
public int handleEvent(Event event)
{
if (event instanceof UnitGainedEvent)
{
UnitGainedEvent unitGainedEvent = (UnitGainedEvent) event;
// things to do if I lost a unit
}
else if (event instanceof UnitLostEvent)
{
UnitLostEvent unitLostEvent = (UnitLostEvent) event;
// things to do if I lost a unit
}
// etc.
}
Cependant, je n'aime pas vraiment avoir à distribuer les événements aux classes d'événements spécifiques. Maintenant, rappelant que la surcharge de méthode peut être utilisée pour invoquer différentes méthodes selon le type d'exécution d'un paramètre, j'ai rapidement trouvé une solution brillante, élégante comme simple: je pourrais créer une classe de base avec une implémentation vide de handleEvent (Event), et ont simplement des sous-classes qui reçoivent les événements qui les intéressent en créant une méthode handleEvent (UnitGainedEvent unitGainedEvent), par exemple. Voulant assurer qu'il travaillerait je mis en place un test rapide:
public class Main
{
public static void main(String[] args)
{
handleEvent(new UnitGainedEvent(null));
}
public static void handleEvent(Event event)
{
System.out.println("Handling generic Event");
}
public static void handleEvent(UnitGainedEvent event)
{
System.out.println("Handling UnitGainedEvent");
}
}
Et à ma grande satisfaction, ce code imprime en fait « Manipulation UnitGainedEvent ». Donc, je me suis mis à la mise en œuvre.
Ma classe de base des composants ressemble à ceci: (Eh bien, pas vraiment Ceci est la classe composant dépouillé de tout pas pertinent au problème que je voudrais démontrer..)
public class Component
{
public void handleEvent(Event event)
{
System.out.println("Handling Event");
}
}
Et c'est un exemple d'une sous-classe:
public class SomeComponent extends Component
{
public void handleEvent(UnitGainedEvent unitGainedEvent)
{
System.out.println("Handling UnitGainedEvent");
}
}
afin de tester la configuration, j'utilise la classe principale suivante:
public class Main
{
public static void main(String[] args)
{
Component component = new SomeComponent();
component.handleEvent(new UnitGainedEvent(null));
}
}
Donc, je cours le code, et à ma grande surprise, le résultat est un «Handling Event» soigneusement imprimé. Chose intéressante, si je change le type de la variable de composant à SomeComponent, fait imprimer 'Handling UnitGainedEvent.' Pour une raison ou une autre, le système invoque aveuglément la méthode handleEvent (Event) de la classe Component, au lieu de surcharger handleEvent de SomeComponent (UnitGainedEvent). (Je serais intéressé d'entendre le raisonnement de Sun derrière cela, pensais que ce n'était pas vraiment pertinent à ma question - pas comme ils vont le réparer juste parce qu'une poignée de personnes trouveraient cela très utile.
Scouring the net me dit que d'autres personnes ont rencontré le même problème. Très peu de gens, à partir de la quantité infime d'informations que je trouve, mais les gens néanmoins, bien que je trouve plus d'informations sur la surcharge de la méthode générale et le dépassement que j'ai jamais voulu savoir. Cependant, à la fin, je n'arrive pas à trouver une solution. Maintenant, ma question (assez évidente) est, y a-t-il un moyen de contourner ce problème? A défaut, quelqu'un peut-il penser ou m'aider à trouver une autre solution tout aussi pratique? Editer: J'ai peine à croire que j'ai des réponses après seulement dix minutes. Je suis agréablement surpris. :) Cependant, la plupart des réponses jusqu'à présent suggèrent sous une forme ou une autre que je fais une méthode séparée pour chaque type d'événement possible. Techniquement, c'est possible, mais cela exigerait que je revienne dans le code et que j'ajoute une nouvelle méthode chaque fois que quelqu'un propose un nouveau type d'événement. Ce que j'ai appris est une mauvaise pratique de codage. (De plus, j'ai déjà plus de 20 types d'événements, et je n'ai même pas encore terminé.) Au lieu de cela, je préfère utiliser la solution impliquant le moulage, comme décrit ci-dessus. Au moins de cette façon, je peux m'assurer que les types d'événements inconnus sont simplement ignorés, me laissant libre de ne gérer que les événements où je veux les utiliser. J'espère vraiment une solution qui combine le meilleur des deux cependant. Pas de casting, et pas de retour dans mon code pour chaque type d'événement.
Un grand merci à l'avance, Loid Thanead
Pour plus d'informations sur les raisons de cette situation, voir ici. http://stackoverflow.com/questions/321864/java-dynamic-binding-and-method-overriding/322234#322234 – Robin