Hourra ! La version française est enfin sortie ! Laissez-nous un message svp, si vous voulez nous faire part de vos commentaires ou signaler une erreur.
Commande

Commande en Java

La Commande est un patron de conception comportemental qui convertit des demandes ou des traitements simples en objets.

Cette conversion permet de différer ou d’exécuter à distance des commandes, de gérer un historique de commandes, etc.

Utilisation du patron de conception en Java

Complexité :

Popularité :

Exemples d’utilisation : La commande est très répandue en Java. Elle est souvent utilisée comme une alternative aux callbacks, pour paramétrer les éléments d’une UI avec des actions. Elle est également utilisée pour mettre des tâches dans une file d’attente, suivre un historique de traitements, etc.

Voici quelques exemples tirés des bibliothèques principales de Java :

Identification : Si vous voyez un ensemble de classes qui représentent des actions spécifiques (comme « Copier », « Coller », « Envoyer », « Imprimer », etc.), il s’agit peut-être d’un patron commande. Ces classes doivent implémenter la même interface ou classe abstraite. Les commandes doivent implémenter elles-mêmes les actions pertinentes ou déléguer les tâches à des objets séparés (les récepteurs). La dernière pièce du puzzle est l’identification d’un demandeur. Cherchez une classe qui accepte des objets commande dans les paramètres de ses méthodes ou de son constructeur.

Commandes d’éditeur de texte et annulation

Dans cet exemple, chaque interaction de l’utilisateur avec l’éditeur de texte crée de nouveaux objets commande. Après avoir lancé toutes ses actions, une commande est poussée dans la pile de l’historique.

Pour pouvoir lancer le traitement d’annulation, l’application prend la dernière commande exécutée de l’historique et soit elle exécute l’action inverse, soit elle restaure l’état passé de l’éditeur qui a été sauvegardé par cette commande.

commands

commands/Command.java: Commande de base abstraite

package refactoring_guru.command.example.commands;

import refactoring_guru.command.example.editor.Editor;

public abstract class Command {
    public Editor editor;
    private String backup;

    Command(Editor editor) {
        this.editor = editor;
    }

    void backup() {
        backup = editor.textField.getText();
    }

    public void undo() {
        editor.textField.setText(backup);
    }

    public abstract boolean execute();
}

commands/CopyCommand.java: Copie le texte sélectionné dans le presse-papiers

package refactoring_guru.command.example.commands;

import refactoring_guru.command.example.editor.Editor;

public class CopyCommand extends Command {

    public CopyCommand(Editor editor) {
        super(editor);
    }

    @Override
    public boolean execute() {
        editor.clipboard = editor.textField.getSelectedText();
        return false;
    }
}

commands/PasteCommand.java: Colle le texte depuis le presse-papiers

package refactoring_guru.command.example.commands;

import refactoring_guru.command.example.editor.Editor;

public class PasteCommand extends Command {

    public PasteCommand(Editor editor) {
        super(editor);
    }

    @Override
    public boolean execute() {
        if (editor.clipboard == null || editor.clipboard.isEmpty()) return false;

        backup();
        editor.textField.insert(editor.clipboard, editor.textField.getCaretPosition());
        return true;
    }
}

commands/CutCommand.java: Coupe le texte dans le presse-papiers

package refactoring_guru.command.example.commands;

import refactoring_guru.command.example.editor.Editor;

public class CutCommand extends Command {

    public CutCommand(Editor editor) {
        super(editor);
    }

    @Override
    public boolean execute() {
        if (editor.textField.getSelectedText().isEmpty()) return false;

        backup();
        String source = editor.textField.getText();
        editor.clipboard = editor.textField.getSelectedText();
        editor.textField.setText(cutString(source));
        return true;
    }

    private String cutString(String source) {
        String start = source.substring(0, editor.textField.getSelectionStart());
        String end = source.substring(editor.textField.getSelectionEnd());
        return start + end;
    }
}

commands/CommandHistory.java: Historique des commandes

package refactoring_guru.command.example.commands;

import java.util.Stack;

public class CommandHistory {
    private Stack<Command> history = new Stack<>();

    public void push(Command c) {
        history.push(c);
    }

    public Command pop() {
        return history.pop();
    }

    public boolean isEmpty() { return history.isEmpty(); }
}

editor

editor/Editor.java: GUI de l’éditeur de texte

package refactoring_guru.command.example.editor;

import refactoring_guru.command.example.commands.*;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class Editor {
    public JTextArea textField;
    public String clipboard;
    private CommandHistory history = new CommandHistory();

    public void init() {
        JFrame frame = new JFrame("Text editor (type & use buttons, Luke!)");
        JPanel content = new JPanel();
        frame.setContentPane(content);
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        content.setLayout(new BoxLayout(content, BoxLayout.Y_AXIS));
        textField = new JTextArea();
        textField.setLineWrap(true);
        content.add(textField);
        JPanel buttons = new JPanel(new FlowLayout(FlowLayout.CENTER));
        JButton ctrlC = new JButton("Ctrl+C");
        JButton ctrlX = new JButton("Ctrl+X");
        JButton ctrlV = new JButton("Ctrl+V");
        JButton ctrlZ = new JButton("Ctrl+Z");
        Editor editor = this;
        ctrlC.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                executeCommand(new CopyCommand(editor));
            }
        });
        ctrlX.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                executeCommand(new CutCommand(editor));
            }
        });
        ctrlV.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                executeCommand(new PasteCommand(editor));
            }
        });
        ctrlZ.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                undo();
            }
        });
        buttons.add(ctrlC);
        buttons.add(ctrlX);
        buttons.add(ctrlV);
        buttons.add(ctrlZ);
        content.add(buttons);
        frame.setSize(450, 200);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    private void executeCommand(Command command) {
        if (command.execute()) {
            history.push(command);
        }
    }

    private void undo() {
        if (history.isEmpty()) return;

        Command command = history.pop();
        if (command != null) {
            command.undo();
        }
    }
}

Demo.java: Code client

package refactoring_guru.command.example;

import refactoring_guru.command.example.editor.Editor;

public class Demo {
    public static void main(String[] args) {
        Editor editor = new Editor();
        editor.init();
    }
}

OutputDemo.png: Résultat de l’exécution

Commande dans les autres langues

Patrons de conception : Commande en C# Patrons de conception : Commande en C++ Patrons de conception : Commande en PHP Patrons de conception : Commande en Python Patrons de conception : Commande en Ruby Patrons de conception : Commande en Swift Patrons de conception : Commande en TypeScript Patrons de conception : Commande en Go