J'ai une classe de commande comme suit:Comment utiliser Class.cast() correctement?
public class Command {
...
private String commandName;
private Object[] commandArgs;
...
public void executeCommand() {}
}
J'ai aussi une sous-classe de commandement, AuthenticateCommand:
public class AuthenticateCommand extends Command {
...
@Override
public void executeCommand() {
...
}
}
Maintenant, imaginez une classe, serveur, qui a une méthode processCommand (commande de commande). Il prend la commande param, inspecte le champ commandName et utilise ce nom pour transtyper la commande dans une sous-classe de la commande responsable de l'implémentation de la logique de commande. Dans cet exemple, vous pouvez avoir une commande avec un nom de commande "authenticate" et le nom d'utilisateur et pw stockés dans le tableau commandArgs. processCommand() transtype la commande en AutheticateCommand et appelle la méthode executeCommand(). Je suis en train d'y arriver avec ce qui suit (commandMap est juste une carte qui associe un commandName à son nom de classe implementor):
public void processCommand(Command command) {
String commandName = command.getCommandName();
String implementorClassString = commandMap.get(commandName);
try {
Class implementorClass = Class.forName(implementorClassString);
Object implementor = implementorClass.cast(command);
Method method = implementorClass.getDeclaredMethod("executeCommand", null);
method.invoke(implementor);
} catch (ClassNotFoundException e) {
logger.error("Could not find implementor class: " + implementorClassString, e);
} catch (NoSuchMethodException e) {
logger.error("Could not find executeCommand method on implementor class: " + implementorClassString, e);
} catch (IllegalAccessException e) {
logger.error("Could not access private member/method on implementor class: " + implementorClassString, e);
} catch (InvocationTargetException e) {
logger.error("Could not invoke executeCommand method on implementor class: " + implementorClassString, e);
}
}
L'appel à implementorClass.cast() jette un ClassCastException. Ne devrait-il pas pouvoir descendre à la classe AuthenticateCommand de cette manière?
MISE À JOUR
Un peu plus fond. La classe Server gère plus que simplement AuthenticateCommands. Il pourrait y avoir n'importe quel nombre de sous-classes de commande, selon le projet. J'essaye de le rendre simple pour quelqu'un écrivant un client pour passer un objet de commande sérialisé avec juste un nom et des arguments. Je pourrais forcer le client à "connaitre" AuthenticateCommand et tous les autres, puis sérialiser ceux-ci et les passer, mais cela semble sous-optimal car la seule différence entre les sous-classes est l'implémentation de executeCommand, dont le client ne se soucie pas ou savoir. Donc, je veux juste un moyen de faire passer le client à la classe parente, et utiliser les données dans cette classe parente pour le convertir en sous-classe appropriée. Je suppose que je pourrais utiliser newInstance() au lieu de lancer et juste créer un nouvel objet, mais cela semble inutile. Je suppose que je pourrais également faire disparaître le concept de sous-classes manipulant la logique et les déplacer dans des méthodes, et ensuite processCommand appelle la méthode appropriée. Cela me semble aussi bien.
Je pense que vous n'avez pas remarqué. Il essaie de lancer Command to AuthenticateCommand en fonction de commandName passé. Ainsi, Method reçoit réellement l'objet Command et non AuthenticateCommand. – YoK
Jon a raison, c'est juste un polymorphisme, ou plutôt un manque de compréhension de son fonctionnement. –
@YoK - la distribution (comme présentée ici) n'est pas nécessaire, Richard lance l'instance de commande sur le type de classe implenting mais stocke le résultat dans une variable 'Object' ... –