Partage
  • Partager sur Facebook
  • Partager sur Twitter

Alternative au switch/case

Conseil pour un nouveau développeur

Sujet résolu
    21 janvier 2011 à 14:30:38

    Bonjour !

    Je suis un nouveau développeur Java et il m'as été assigné le développement d'un serveur. Tout se passe plutôt bien jusqu'à présent, j'ai pu coder les choses proprement, les objets Server, Socket, Channel et compagnie sont fort bien conçu...

    Le problème, c'est que j'ai besoin d'établir des comportements différents en fonction du type de message.
    En C++, la meilleure manière de faire cela, c'est quelque chose comme ça :

    struct CommandAssociation
    {
      private:
        typedef void (TheClass::*methodPointer)(void);
    
      public:
        methodPointer exec;
        unsigned int  flag;
    };
    
    CommandAssociation commands[] =
    {
      { &TheClass::Command1, 0 },
      { &TheClass::Command2, 1 },
      { &TheClass::Command3, 2 }
    };
    
    void TheClass::ExecCommand(int cmd)
    {
      for (unsigned int i = 0 ; i < 3 ; ++i)
      {
        if (commands[i].flag == cmd)
        {
          (this->*(commands[i].exec))();
          break ;
        }
      }
    }
    


    C'est une alternative très efficace et surtout très flexible à un switch/case : j'ai l'habitude de faire cela quand je ne connais pas le nombre de fonctionnalités que j'intégrerais avec un tel système : ainsi pour un ajout/retrait de fonctionnalité, on sait tout de suite ou regarder, et on a un minimum de changement de code à faire.

    Comment obtenir un résultat similaire en Java ?
    • Partager sur Facebook
    • Partager sur Twitter
      21 janvier 2011 à 15:19:31

      JE vois deux possibilités explorables :
      1 - une interface contenant une méthode unique jouant en quelque sorte le rôle de ton pointeur de fonction
      2 - utiliser la réflexion

      Exemple n°1 :
      public class Server {
      interface Command {
      public void exec () ;
      }
      class Command1 implements Command {
      public void exec () { System.out.println("Command 1"); }
      }
      class Command2 implements Command {
      public void exec () { System.out.println("Command 2"); }
      }
      
      Map<Integer,Command> commands = new HashMap<Integer,Command>();
      public Server () {
      commands.add(1, new Command1());
      commands.add(2, new Command2());:
      }
      
      public void handleMessage (int msg) {
      commands.get(msg).exec();
      }
      


      Exemple n°2 :
      class Server {
      public void do1 () { System.out.println("Do 1"); }
      public void do2 () { System.out.println("Do 2"); }
      
      public void handleMessage (int msg) {
      Method m = this.getClass().getMethod("do"+msg);
      m.invoke(this);
      }
      
      }
      


      J'ai volontairement simplifié en supprimant notamment la gestion des exceptions. Mais ça te suffit pour te faire une idée.

      AVantage de la solution n°1 : très bon modèle objet, potentiellement très extensible.
      Inconvénient de la solution n°1 : il te faut une classe par type de commande, à moins que tu arrives à être suffisament habile pour regrouper, mais c'est pas facile.
      Avantage de la solution n°2 : tout est regroupé dans la même classe, ça peut être utile. C'est aussi gobalement moins verbeux que la première solution.
      Inconvénient de la solution n°2 : la rréflexion est réputé extrêmement lente, et ce n'est pas forcément toujours facile à suivre. En plus c'est plutôt classé mauvaise pratique, et c'est pas véritablement extensible, du moins pas autant que la première.

      Je te conseille donc vivement la première...
      • Partager sur Facebook
      • Partager sur Twitter
        21 janvier 2011 à 17:39:21

        Merci !

        C'est bête que la deuxième méthode soit "salle" (d'un autre côté, comparer des String pour obtenir des méthodes, c'est sûr que ça pourra pas aller très vite).

        Je vais suivre ton conseil et utiliser la première. Ça fait beaucoup de ligne de codes, mais l'élégance et la performance n'ont pas de prix !

        EDIT: Ah, par contre la méthode pour ajouter dans une Map n'est pas "add" mais "put".
        • Partager sur Facebook
        • Partager sur Twitter
          21 janvier 2011 à 20:11:44

          Citation

          EDIT: Ah, par contre la méthode pour ajouter dans une Map n'est pas "add" mais "put".


          J'ai tapé le code dans la réponse rapide à la va-vite, désolé. L'essentiel était de bien voir le principe.
          • Partager sur Facebook
          • Partager sur Twitter

          Alternative au switch/case

          × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
          × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
          • Editeur
          • Markdown