Publicité
+ Répondre à la discussion
Affichage des résultats 1 à 4 sur 4
  1. #1
    Invité de passage
    Inscrit en
    mars 2012
    Messages
    4
    Détails du profil
    Informations forums :
    Inscription : mars 2012
    Messages : 4
    Points : 0
    Points
    0

    Par défaut Pattern commande et modèle complexe

    Je travaille actuellement sur un éditeur d'analyses syntaxiques (des forêts d'arbres), et je l'ai doté de fonctionnalités undo/redo en utilisant le pattern commande.

    Mais j'ai du mal à trouver une architecture qui me satisfasse vraiment. Je m'explique :

    Les opérations sur le modèle sont assez complexes : supprimer un noeud entraîne par exemple une réorganisation des arcs qui constituent mon graphe.

    Bref, pour enregistrer tout ce qui doit être fait et/ou défait par la commande, en gardant l'encapsulation du modèle, la seule manière que je vois est de faire créer les commandes par le modèle. Mais d'une certaine manière, pour rester cohérent, cela supposerait que le modèle ne soit doté que de méthodes créant des commandes (et de méthodes permettant de consulter les données), et d'aucune méthode de modification directe.

    ça me semble logique, mais je ne vois nulle part d'implémentation de ce genre. Est-ce que je suis à l'ouest ?

    Bien cordialement,
    R7

  2. #2
    Membre chevronné
    Inscrit en
    janvier 2011
    Messages
    231
    Détails du profil
    Informations forums :
    Inscription : janvier 2011
    Messages : 231
    Points : 665
    Points
    665

    Par défaut

    Typiquement le pattern Command met en jeu 3 parties :

    • Le client qui crée l'objet commande
    • L'invoker qui l'exécute
    • Le receiver qui contient les méthodes appelées par la commande


    Dans le cas de Undo/Redo, le client va créer la commande et en général la faire exécuter tout de suite au UndoRedoManager/CommandManager (l'invoker). En effet empiler une commande dans le stack Undo/Redo signifie aussi l'exécuter : l'étape préalable avant qu'on puisse faire un Undo/Redo est qu'on ait déjà fait un Do.

    D'après ce que je comprends, tu souhaiterais que le client soit aussi le receiver, c'est à dire que l'objet qui va créer la commande et demander au manager de l'empiler soit aussi celui qui déclare les méthodes exécutées dans cette commande ?

    Je pense que tu n'as pas dû tomber souvent sur ce genre d'implémentation car dans mon expérience, une commande "undoable" ne se limite pas à un appel de méthode mais est souvent constituée d'une séquence d'appels à plusieurs méthodes de divers objets. Le client/invoker est souvent un objet coordinateur au courant du contexte d'exécution de l'application, et pas le modèle lui-même.

    cela supposerait que le modèle ne soit doté [...] d'aucune méthode de modification directe.
    Par contre quand tu dis ça, tu penses à externaliser ces méthodes ailleurs que dans le modèle ou à passer des méthodes anonymes/lambda expressions à la commande ?

    Personnellement, j'ai implémenté un UndoRedoManager (en C#) en utilisant des lambda expressions et des closures (on "close" les données sur la commande passée au UndoRedoManager afin de pouvoir opérer sur ces mêmes données plus tard lorsqu'on fera un Undo ou un Redo) et ça marche pas mal.

  3. #3
    Invité de passage
    Inscrit en
    mars 2012
    Messages
    4
    Détails du profil
    Informations forums :
    Inscription : mars 2012
    Messages : 4
    Points : 0
    Points
    0

    Par défaut

    En fait, j'ai actuellement :

    * le client C est dans la couche graphique (l'action associée au menu)

    * l'invoker U est la classe Swing UndoManager

    * le receiver R est la façade de mon modèle.

    Donc, dans mon architecture actuelle, le client C demande à R de créer la commande (qui est exécutée dans la foulée), puis l'ajoute à U.

    Le truc, justement, est que l'exécution de la commande, pour être correcte, doit modifier pas mal de données dans le modèle. Je ne veux pas rendre ces données accessibles individuellement, du moins en modification.

    Du coup, je dédouble plus ou moins la logique : j'utilise UndoAbleEdit d'un côté, et, dans mon modèle, j'ai des classes internes (c'est en java, donc en gros des clôtures dans des langages plus riches côté fonctionnel), qui implémentent leur propre version de Commande, et l'implantation que j'utilise d'UndoAbleEdit sert d'adaptateur.

    L'objet créé par le modèle contient la liste des liens à supprimer, des liens à ajouter, des noeuds à supprimer et des noeuds à ajouter.

    C'est un peu tordu, et, même si ça tourne (le code est déjà écrit, je me demande comment mieux l'architecturer), ça me semble fragile.

    J'ai pensé à placer UndoAbleEdit directement dans mon modèle et économiser une couche serait raisonnable - c'est un type de fonctionnalité qui n'est pas réellement spécifique aux interfaces Swing.

    Mais, le fond du problème est le suivant :

    Dans la plupart des exemples de Commande, à la création de la commande, (ou à sa première exécution) on peut sans trop de problème préparer le "undo" sans casser l'encapsulation du receiver, éventuellement avec un peu d'aide.

    Par exemple, pour une commande "suppression" dans un traitement de texte, il faut récupérer la zone de texte supprimée pour pouvoir la recoller ensuite, mais c'est assez naturel à faire, ne serait-ce que parce qu'on aura aussi besoin de ce type de fonctionnalité pour les copier/coller, etc...

    Dans mon cas, la commande de suppression dans un graphe fait plein de plomberie, et je n'ai pas envie de la placer au niveau de l'interface.

    On sent qu'on aimerait quelque chose qui ressemblerait à un mémento, mais qui n'en est pas exactement un (il se rappelle des modifications et pas un état)...

  4. #4
    Membre chevronné
    Inscrit en
    janvier 2011
    Messages
    231
    Détails du profil
    Informations forums :
    Inscription : janvier 2011
    Messages : 231
    Points : 665
    Points
    665

    Par défaut

    Je crois que je vois le problème même si c'est un peu obscur sans exemple et sans connaître le contexte.

    Je vois une manière de résoudre ça : le client crée une commande (supprimer un noeud par exemple) qui est en réalité composite et va passer le relais au modèle pour y attacher une chaîne de sous-commandes associées (réorganiser les arcs, etc). Le modèle connaît chaque sous-opération et sait comment faire un Undo sur chacune donc on est OK.

    Le UndoManager connait la notion de commande composite et sait que pour en annuler une il faut annuler toutes ses sous-commandes en séquence.

Liens sociaux

Règles de messages

  • Vous ne pouvez pas créer de nouvelles discussions
  • Vous ne pouvez pas envoyer des réponses
  • Vous ne pouvez pas envoyer des pièces jointes
  • Vous ne pouvez pas modifier vos messages
  •