Précédent   Forum du club des développeurs et IT Pro > Général Développement > ALM > Design Patterns
Design Patterns Forum d'entraide sur l'utilisation des Design Patterns (GRASP, GOF, etc.) et la recherche de solution à des problèmes récurrents. Avant de poster : Les tutoriels sur les DP. Privilégiez le forum Architecture pour vos questions sur les patterns architecturaux (PAC, MVC, etc.)
Partagez cette discussion sur d'autres réseaux sociaux : Viadeo Twitter Google Facebook Digg Delicious MySpace Yahoo
Réponse
 
Outils de la discussion
Publicité
'
Vieux 20/03/2012, 19h33   #1
ramses007
Invité de passage
 
Inscription : 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
ramses007 est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 21/03/2012, 11h34   #2
Luckyluke34
Membre éprouvé
 
Inscription : janvier 2011
Messages : 156
Détails du profil
Informations forums :
Inscription : janvier 2011
Messages : 156
Points : 410
Points : 410
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.

Citation:
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.
Luckyluke34 est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 21/03/2012, 16h59   #3
ramses007
Invité de passage
 
Inscription : mars 2012
Messages : 4
Détails du profil
Informations forums :
Inscription : mars 2012
Messages : 4
Points : 0
Points : 0
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)...
ramses007 est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 21/03/2012, 18h05   #4
Luckyluke34
Membre éprouvé
 
Inscription : janvier 2011
Messages : 156
Détails du profil
Informations forums :
Inscription : janvier 2011
Messages : 156
Points : 410
Points : 410
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.
Luckyluke34 est déconnecté   Envoyer un message privé Réponse avec citation 00
Réponse
Outils de la discussion

Navigation rapide


Fuseau horaire GMT +2. Il est actuellement 04h43.


 
 
 
 
Partenaires

Hébergement Web