Partage
  • Partager sur Facebook
  • Partager sur Twitter

Logiciel de CAO, Design pattern Command & Composit

    18 mai 2019 à 11:30:17

    Bonjour à toutes et à tous!

    J'entame aujourd'hui un tout nouveau projet: réaliser un tout petit logiciel de CAO en Qt/QML.

    Très minimaliste l'utilisateur doit pouvoir ajouter des points sur une carte, les relier par des lignes, faire des formes, etc.

    Sans rentrer dans les détails, je veux pouvoir faire des Undo/Redo sur mes commandes, et sauvegarder toutes ces commandes dans un fichier, afin de pouvoir "rejouer" la création de mon projet: ce ne sera pas les objets créés qui seront sauvegardés, mais la recette du projet.

    Le concept du pattern Command a bien été assimilé. Je cherche aujourd'hui un moyen élégant de sérialiser les commandes et leurs arguments sous forme d'un fichier texte (json). Ce qui m'embête le plus est de devoir créer une sorte de compilateur pour transformer ces instructions "textuelles" en commandes et vice-versa. Je souhaite éviter un couplage trop fort entre le parser et les commandes.

    Quelques idées:

    - chaque commande invoquée pourrait posséder des méthodes de sérialisation... 

    - Créer la recette avec des instructions directement exécutable par QtScript...

    Si vous avez des idées/suggestions, je suis preneur !

    -
    Edité par totolito 18 mai 2019 à 11:31:33

    • Partager sur Facebook
    • Partager sur Twitter
      18 mai 2019 à 12:48:34

      Salut,

      La sauvegarde de tes commandes, quelle que soit la forme qu'elle pourra prendre, ne sera jamais un problème:  Comme chaque commande sait -- a priori -- quels sont les paramètres qu'elle a recu, leur type et leur valeur, une simple fontion save ou, de manière plus "conceptuellement correcte" : une abstraction (une class Saver ???) permettant de parcourir l'ensemble des instructions, d'en extraire les informations pertinente, et de les "injecter" dans un fichier en respectant le format de sauvegarde, sera très facile à mettre en place ;).

      L'un dans l'autre, si le nombre de commande reste relativement faible et particulièrement stable, le patron de conception visiteur (ou, du moins, la mise en place du double dispatch, sous une forme ou une autre) pourrait parfaitement faire l'affaire

      Le problème vient de "l'effet miroir", car, si tu "prend la peine" d'écrire dans un fichier les informations qui te permettront de rejouer la recette du projet de ton utilisateur, tu dois forcément t'attendre à vouloir... lire ces informations afin de les récupérer (et pouvoir, pourquoi pas, "rejouer" la recette indiquée) : pour chaque entrée, il faut la sortie correspondante ;)

      L'énorme avantage, c'est que tu devrais -- a priori -- avoir déjà fait le plus dur.  Car je présume (ou, du moins, je l'espère) que tu as pris le temps de mettre en place un patron de conception de type "fabrique" (ou, plus vraisemblablement de type "builder") pour créer tes différentes instances de commandes.

      Si ce n'est pas le cas, je te conseille ardemment de t'y mettre : non seulement, cela te simplifiera énormément la vie lorsque tu voudras lire les sauvegardes (j'y viens très rapidement :D ), mais cela te facilitera énormément la vie par la suite, en te mettant dans une situation dans laquelle SRP et OCP seront mieux respectés, et en t'évitant de te retrouver avec un truc tout à fait ingérable parce que tu auras décidé d'ajouter une dizaine de nouvelles commandes au fil du temps.

      Maintenant, si je dis que c'est un avantage, c'est parce que le système de lecture de tes sauvegardes ne devra dépendre... que de ton "gestionnaire" de commandes, et de la fabrique (ou du builder) qui permet de les créer.

      Après tout, que tu crées une commande sur base des informations que tu trouve dans formulaire affiché spécifiquement pour permettre à l'utilisateur de les introduire, sur base des informations extraites depuis un fichier quelconque ou même sur base d'informations obtenues depuis un serveur distant...  Ca ne change absolument rien à l'affaire : au final, on en revient toujours à la même logique qui est

      1. sélectionner la commande qui doit être créée
      2. créer la commande sélectionnée en lui fournissant les paramètres adéquats
      3. s'arranger pour que la commande soit maintenue en mémoire dans le "gestionnaire de commande"

      Si bien que les seules choses que ton parser devra être capable de faire consistent à

      • Pouvoir déterminer la commande qui doit être créée
      • Etre en mesure de convertir les informations supplémentaires de manière à obtenir les paramètres "qui vont bien" pour la création de la commande
      • faire appel à la fabrique (ou au builder) en lui indiquant quelle commande créer et en lui fournissant les paramètres requis

      Quant au maintien en mémoire au sein du gestionnaire de commande, ce pourrait parfaitement ne pas être de son domaine, vu que, a priori, c'est la fabrique (ou le builder) qui prendra cela en charge ;)

      Bien sur, le parser devra aussi s'assurer de la cohérence des informations qu'il extrait.  Car toute donnée externe doit être considérée comme "suspecte jusqu'à preuve du contraire".

      Mais ce n'est -- a priori -- pas ce qui est le plus compliqué ;)

      Enfin, j'aurais tendance à te conseiller de trouver une bibliothèque spécialisée dans le traitement des fichiers json, vu que c'est le format vers lequel tu souhaite te tourner.  Cela devrait te faciliter énormément la tâche en t'évitant d'avoir à recréer une roue qui risque fort d'être carrée dans un premier temps ;)

      • Partager sur Facebook
      • Partager sur Twitter
      Ce qui se conçoit bien s'énonce clairement. Et les mots pour le dire viennent aisément.Mon nouveau livre : Coder efficacement - Bonnes pratiques et erreurs  à éviter (en C++)Avant de faire ce que tu ne pourras défaire, penses à tout ce que tu ne pourras plus faire une fois que tu l'auras fait
        18 mai 2019 à 12:49:24

        Salut !

        Je sais que les logiciels de CAO stockent la "recette" comme tu dis (le feature tree), mais aussi le modèle final. Les deux :)

        • Partager sur Facebook
        • Partager sur Twitter

        Recueil de code C et C++  http://fvirtman.free.fr/recueil/index.html

          20 mai 2019 à 13:12:46

          Bonjour koala01 et Fvirtman

          Merci pour cette réponse détaillée. 

          J'hésite encore sur quelques points.

          1°) ReadWrite des commandes de ma recette dans un json: Comment faire correspondre un texte (nom de ma commande) à la classe Commande à instancier de manière transparente. Peut-être utiliser les Metadonnées Qt...

          2°) Editer une commande déjà dans la recette: utiliser une classe de base pour mes commandes de type QAbstractItemModel me semble une bonne approche

          3°) Sachant que je vais avoir des commandes différentes, comment trouver l'interface graphique qui correspond à la commande que je veux éditer. J'avais imaginé que chaque commande pourrait renvoyer le QWidget d'édition mais ne serait-ce pas une erreur de conception... 


          @Fvirtman: Oui mais je vois pas trop l'intérêt à part éviter de reconstruire le projet à chaque chargement...

          Merci de votre intérêt !!

          -
          Edité par totolito 20 mai 2019 à 21:08:43

          • Partager sur Facebook
          • Partager sur Twitter
            20 mai 2019 à 14:31:16

            totolito a écrit:

            @Fvirtman: Oui mais je vois pas trop l'intérêt à part éviter de reconstruire le projet à chaque chargement...

            Oh il est très simple : AUCUN logiciel n'est dénué de bugs, et de modifications nécessaires d'une version à l'autre, y compris du noyau. Certaines fonctions mathématiques sont améliorées, mais peuvent donc donner un résultat un tout petit peu différent que la version d'avant.

            Et si cette différence est autour d'une limite, alors t'es mort. Et il y a plein de cas ou les features se rejouent mal.

            Je vais donner un exemple concret plus parlant. Tu fais une partie parfaite de Mario Bros, tu enregistres les touches (le moment tu t'appuies sur chaque bouton), pour rejouer toute une partie parfaite rien qu'avec ça.

            Mais pour la version d'après, tu as constaté que les tortues bougent un peu trop doucement, on va les faire accélérer un chouia... Trois fois rien...

            Et résultat, quand tu rejoues tes touches, et bien au lieu de sauter juste avant la tortue, elle te tue. Et tout le reste est donc foiré....

            Pour en revenir à la CAO, c'est à cause de toutes ces petites modifications ou corrections de bugs, même mineurs d'une version à une autre, qu'on ne peut pas se contenter de juste sauvegarder les features, on enregistre aussi le résultat fini.

            • Partager sur Facebook
            • Partager sur Twitter

            Recueil de code C et C++  http://fvirtman.free.fr/recueil/index.html

              20 mai 2019 à 16:42:13

              @Fvirtman

              Oui je vois bien le problème. Sauf que devant gérer le undo, j'avais pris comme postulat d'effacer le résultat et de rejouer toutes les features. 

              Avec ton approche, dois-je passer les features déjà jouée en "read-only", c-a-d ne pas re-générer les points sérialisés?? Ça me paraît assez limitant...

              @koala01

              Ma fabrique de commandes pourrait effectivement utiliser des objets Json pour refabriquer les commandes. Mais lorsque je souhaite les créer la première fois, penses-tu que je devrais passer par la même entrée? Ca me contraindrait à créer un objet json puis à le passer à la fabrique... 

              Au lieu de :

              maCommande = CreateCommand(CommandType::Point, "MonPoint", coord1);

              j'aurais:

              jsonObj["Type"] = "CreatePoint";

              jsonObj["name"] = "MonPoint";

              jsonObj["coord"] = coord1.toString();

              maCommande = CreateCommand(jsonObj);

              Au moins je n'ai qu'une méthode d'entrée... 

              -
              Edité par totolito 21 mai 2019 à 10:09:51

              • Partager sur Facebook
              • Partager sur Twitter

              Logiciel de CAO, Design pattern Command & Composit

              × 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