IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Voir le flux RSS

Un bon développeur est un développeur flemmard !

[Java][Design Pattern]Comment faire le undo/redo? Le principe de base !

Noter ce billet
par , 05/11/2014 à 11h59 (3613 Affichages)
Bonjour,

Si vous êtes développeur, un jour ou l'autre, on va vous demander la fonction undo/redo. Si vous ne connaissez pas le pattern à utiliser à ce moment là, vous serez désespéré !
Pourtant le pattern est connu et "classique", c'est le pattern "Commande". Personnellement, je préfère le terme "Processeur de commande". Car, il met en évidence la présence d'un PROCESSEUR qui centralise (1).

Le problème du Undo/Redo, c'est la centralisation de l'information ! Il doit y avoir un et un seul endroit qui connait les commandes/actions qui ont été réalisées. Ce qu'on appel le "processeur".

Le processeur est relativement simple :

Il prendre UNE interface en entré (2) :
Code java : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
package org.k.developpez.blog.undoredo;
 
public interface Command {
	public void execute();
	public void undo();
	public boolean canBeUnDone();
}

Il a un historique (3) :
Code java : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
// Historique des commandes réalisée
private List<Command> historic = new ArrayList<Command>();
// Historique des commande annulée (le nom de la variable est foireux)
private List<Command> unDoneHistoric = new ArrayList<Command>();

Les méthodes disponibles sur un processeur sont les suivantes :
Code java : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
	/**
         * Réalise la commande
         */
	public void execute(Command command);
	/**
         * Annule la dernière commande exécute.
         */
	public void undo();
	/**
         * Execute la dernière commande annulée
         */
	public void redo() {
		if(!unDoneHistoric.isEmpty()){
			Command toRedo=unDoneHistoric.get(0);
			unDoneHistoric.remove(0);
			this.execute(toRedo);
		} else {
			System.out.println("Debug processor : No command to redo");
		}
	}
	/**
         * Indique si on peut annuler la dernière commande
         * @return boolean
         */
	public boolean canBeUnDone();
	/**
         * Supprimme l'ensemble de l'historique
         */
	public void reset();
Le plus compliqué étant de mettre à jour les listes d'historique à jour à chaque fois de manière approprié.

Bien-sûr dans une application existante, il va falloir :
Crée le processeur.
Créer les commandes correspondantes à toutes les actions de l'applications.
Remplacer les actions par leur commande :

Code java : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
 
//Anciennement
Lamp lamp = new Lamp();
lamp.switch();
//nouvellement 
Lamp lamp = new Lamp();
SwitchCommand command = new SwitchCommand(lamp);
Processor.getInstance().execute(command);


Ce qu'il faut retenir :
    1. Centralisé (Un processeur)
    2. Normalisé (Une interface **Command**)
    3. Mémorisé (un historique)


C'est les trois principes qui donnent une bonne implémentation du undo/redo


Code en action :
Dans un bût de démonstration, j'ai réalisé un processeur qui gère des commandes sur une lampe dont les sources sont en pièces joints. Ce n'est pas le plus avancé des Processeur de commande que j'ai réalisé, mais celui-ci réalise le undo et le redo de manière correcte.

Voici la trace commanté que donne mon exemple :
===== START TEST org.k.developpez.blog.SwitchCommand =====
Lamp is off
org.k.developpez.blog.SwitchCommand : Execute
Lamp is on
org.k.developpez.blog.SwitchCommand : undo
Lamp is off
org.k.developpez.blog.SwitchCommand : redo
Lamp is on
===== END TEST =====
===== START TEST org.k.developpez.blog.TurnOnCommand =====
Lamp is off
org.k.developpez.blog.TurnOnCommand : Execute
Lamp is on
org.k.developpez.blog.TurnOnCommand : undo // K : La commandeTurnOn passe à l'état on quelques soit l'état de la lampe avant. Il est donc impossible d'avoir la commande inverse ! On ne connais pas l'état d'avant (on ne la pas mémorisé).
Debug processor : No command to undo
Lamp is on
org.k.developpez.blog.TurnOnCommand : redo
Debug processor : No command to redo
Lamp is on
===== END TEST =====
===== START TEST org.k.developpez.blog.TurnOnCommand =====
Lamp is off
org.k.developpez.blog.TurnOnCommand : Execute
Lamp is on
org.k.developpez.blog.TurnOnCommand : undo // K : La commandeTurnOff passe à l'état off quelques soit l'état de la lampe avant. Il est donc impossible d'avoir la commande inverse ! On ne connais pas l'état d'avant (on ne la pas mémorisé).
Debug processor : No command to undo
Lamp is on
org.k.developpez.blog.TurnOnCommand : redo
Debug processor : No command to redo
Lamp is on
===== END TEST =====
Cordialement,
Patrick Kolodziejczyk.

Source :
http://en.wikipedia.org/wiki/Command_pattern#Java
http://fr.wikipedia.org/wiki/Command..._conception%29
Miniatures attachées Fichiers attachés

Envoyer le billet « [Java][Design Pattern]Comment faire le undo/redo? Le principe de base ! » dans le blog Viadeo Envoyer le billet « [Java][Design Pattern]Comment faire le undo/redo? Le principe de base ! » dans le blog Twitter Envoyer le billet « [Java][Design Pattern]Comment faire le undo/redo? Le principe de base ! » dans le blog Google Envoyer le billet « [Java][Design Pattern]Comment faire le undo/redo? Le principe de base ! » dans le blog Facebook Envoyer le billet « [Java][Design Pattern]Comment faire le undo/redo? Le principe de base ! » dans le blog Digg Envoyer le billet « [Java][Design Pattern]Comment faire le undo/redo? Le principe de base ! » dans le blog Delicious Envoyer le billet « [Java][Design Pattern]Comment faire le undo/redo? Le principe de base ! » dans le blog MySpace Envoyer le billet « [Java][Design Pattern]Comment faire le undo/redo? Le principe de base ! » dans le blog Yahoo

Mis à jour 07/11/2014 à 10h07 par kolodz

Catégories
Java , Programmation

Commentaires