Volver a la página principal
sábado 12 octubre 2024
4

Cómo implementar el patrón de diseño Memento en PHP

El patrón de diseño Memento es uno de los patrones de comportamiento que permite guardar y restaurar el estado de un objeto sin violar el principio de encapsulamiento. Este patrón es útil cuando necesitamos poder deshacer o rehacer operaciones, manteniendo un registro de los estados anteriores de un objeto.

En este artículo, veremos qué es el patrón Memento, sus componentes principales y cómo implementarlo en PHP con un ejemplo práctico.

¿Qué es el patrón Memento?

El patrón Memento se utiliza para capturar el estado interno de un objeto sin exponer sus detalles internos, y luego restaurar ese estado cuando sea necesario. Esto permite volver a un estado anterior del objeto, lo que es ideal para implementar funcionalidades de "deshacer" (undo) o "rehacer" (redo).

Componentes principales del patrón Memento

El patrón Memento se compone de tres partes clave:

1. Originador (Originator): El objeto cuyo estado se quiere salvar y restaurar.

2. Memento: El contenedor que almacena el estado del Originador.

3. Cuidador (Caretaker): Gestiona los Mementos, almacenando y restaurando los estados del Originador.

Ventajas del patrón Memento

  • Encapsulamiento: El patrón respeta el principio de encapsulamiento, ya que el estado interno del objeto no es expuesto a través del Memento.
  • Deshacer y rehacer: Se puede implementar una funcionalidad de deshacer y rehacer sin necesidad de alterar el código del Originador.

Cuándo usar el patrón Memento

  • Cuando quieras implementar una funcionalidad de deshacer/rehacer en tu aplicación.
  • Si necesitas guardar el estado de un objeto sin revelar sus detalles internos.
  • Si quieres evitar acoplar el estado de un objeto con clases externas.

Implementación del patrón Memento en PHP

A continuación, implementaremos el patrón Memento en PHP mediante un ejemplo práctico en el que simulamos un editor de texto que puede deshacer los cambios.

1. Clase Memento

La clase Memento será responsable de almacenar el estado del objeto. En este caso, simplemente guardará el texto de un editor.

<?php

class Memento {
    private $state;

    public function __construct(string $state) {
        $this->state = $state;
    }

    public function getState(): string {
        return $this->state;
    }
}

2. Clase Originator

La clase Originator es el objeto que queremos guardar y restaurar. En este ejemplo, será un editor de texto con una propiedad $text. Esta clase puede crear un memento que guarde su estado actual y restaurar su estado desde un memento dado.

<?php

class TextEditor {
    private $text;

    public function __construct() {
        $this->text = "";
    }

    public function write(string $words) {
        $this->text .= $words;
    }

    public function getText(): string {
        return $this->text;
    }

    // Crear un Memento para guardar el estado actual
    public function save(): Memento {
        return new Memento($this->text);
    }

    // Restaurar el estado desde un Memento
    public function restore(Memento $memento) {
        $this->text = $memento->getState();
    }
}

3. Clase Caretaker

El Caretaker será el responsable de manejar los mementos. Esta clase almacenará los diferentes estados del editor de texto, permitiendo deshacer cambios.

<?php

class Caretaker {
    private $history = [];

    public function saveMemento(Memento $memento) {
        $this->history[] = $memento;
    }

    public function getMemento(int $index): ?Memento {
        return $this->history[$index] ?? null;
    }

    public function getHistory(): array {
        return $this->history;
    }
}

4. Ejemplo de uso

Ahora que tenemos las clases necesarias (Memento, TextEditor, y Caretaker), podemos ver cómo se utilizan en conjunto para implementar la funcionalidad de deshacer cambios en el editor de texto.

<?php

// Crear el editor de texto y el cuidador
$editor = new TextEditor();
$caretaker = new Caretaker();

// Escribir algo de texto en el editor
$editor->write("Hola, ");
$editor->write("este es un ");
$editor->write("ejemplo del patrón Memento.");

// Guardar el estado actual
$caretaker->saveMemento($editor->save());

echo "Texto actual: " . $editor->getText() . "\n";

// Escribir más texto
$editor->write(" Añadiendo más texto.");
echo "Texto después de agregar más: " . $editor->getText() . "\n";

// Guardar el nuevo estado
$caretaker->saveMemento($editor->save());

// Restaurar al estado anterior (deshacer)
$editor->restore($caretaker->getMemento(0));
echo "Texto después de deshacer: " . $editor->getText() . "\n";

// Restaurar al último estado (rehacer)
$editor->restore($caretaker->getMemento(1));
echo "Texto después de rehacer: " . $editor->getText() . "\n";

5. Explicación del flujo

1. El TextEditor empieza vacío, pero escribimos varias líneas de texto usando el método write().

2. Guardamos el estado del editor llamando al método save() del TextEditor y almacenamos el memento en el Caretaker mediante saveMemento().

3. Escribimos más texto en el editor y volvemos a guardar el estado actual.

4. Para deshacer los cambios, restauramos el primer memento que guardamos y el editor regresa al estado anterior.

5. Para rehacer, restauramos el último memento que guardamos, recuperando el estado más reciente.

Conclusión

El patrón Memento es una solución elegante cuando se necesita guardar y restaurar el estado de un objeto sin comprometer el encapsulamiento. En PHP, este patrón es fácil de implementar y resulta muy útil para funcionalidades como deshacer/rehacer, editores de texto, o cualquier aplicación que requiera guardar el estado de un objeto en un momento dado.

Mediante el uso de las clases Memento, TextEditor y Caretaker, se puede gestionar el historial de cambios de manera eficiente, garantizando que el código sea mantenible y escalable.

Compartir:
Creado por:
Author photo

Jorge García

Fullstack developer