🚨 ¡Nueva review! ¡Mi teclado ideal! ⌨️ Perfecto para programar, el Logitech MX Keys S . ¡Échale un ojo! 👀

El Patrón de diseño Memento

El botón de "Guardar Partida" para tus objetos.

Escrito por domin el 2 de diciembre de 2025

💾 El Patrón Memento: Viajando en el tiempo

El Patrón Memento (Recuerdo), tiene un objetivo que todos amamos: permitir volver atrás. Su misión es guardar el estado de un objeto para poder restaurarlo después, pero sin romper las reglas de privacidad del objeto.

El problema que resuelve es este:
¿Cómo guardas una copia exacta de un objeto (incluyendo sus variables privadas) para poder restaurarlo luego, sin exponer esas variables privadas al mundo exterior y romper el encapsulamiento?

La respuesta es dejar que el propio objeto cree una “instantánea” (Memento) de sí mismo. Solo él puede leerla, pero otros pueden guardarla.

Diagrama del Patrón Memento.

🎮 1. Un ejemplo sencillo y muy visto: Guardar Partida

Imagina que estás jugando a un videojuego difícil (El Originador):

Concepto (Analogía)

Rol en Memento

Tarea Principal

El Juego / Personaje

Originador (Originator)

El objeto cuyo estado queremos guardar y restaurar.

Archivo de Guardado

Memento

Objeto de valor inmutable que contiene el estado.

La Consola / Jugador

Cuidador (Caretaker)

Guarda los mementos pero no los modifica ni inspecciona.

🛠️ 2. Los tres pilares del patrón Memento

1. Originador

2. Memento

3. Cuidador (Caretaker)

🤔 1. ¿Por qué el Cuidador no debe modificar el Memento?

↩️ 3. Otro ejemplo muy clásico: Deshacer (undo)

El uso más conocido es el comando CTRL+Z en editores de texto. Cada vez que escribes, el editor guarda un Memento en una pila. Al deshacer, saca el último Memento y restaura el estado.

🤔 2. ¿Qué desventaja obvia tiene guardar muchos Mementos?

✅ 4. ¿Por qué usarlo?

  1. Encapsulamiento: Puedes guardar el estado privado sin hacerlo público.
  2. Simplificación: El Originador no tiene que gestionar el historial de versiones, eso lo hace el Cuidador.

❌ 5. Desventaja a considerar

🤔 3. ¿Es el patrón Memento la única forma de implementar 'Deshacer'?

💡 6. Conclusión

El Memento es tu salvación si necesitas implementar “Deshacer” o transacciones con rollback. Es la forma limpia de viajar en el tiempo dentro de tu aplicación.

Infografía Patrón de diseño Memento

🧠 7. Ejemplo práctico en PHP

Vamos a hacer un editor de texto simple con historial.

<?php

// 🔹 1. Memento
class EditorMemento
{
    private string $contenido;

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

    public function getContenido(): string
    {
        return $this->contenido;
    }
}

// 🔹 2. Originador
class EditorTexto
{
    private string $contenido = '';

    public function escribir(string $texto): void
    {
        $this->contenido .= $texto;
        echo "📝 Escrito: '$texto'. Contenido actual: '{$this->contenido}'\n";
    }

    public function guardar(): EditorMemento
    {
        echo "💾 Guardando estado...\n";
        return new EditorMemento($this->contenido);
    }

    public function restaurar(EditorMemento $memento): void
    {
        $this->contenido = $memento->getContenido();
        echo "↩️ Restaurado a: '{$this->contenido}'\n";
    }
}

// 🔹 3. Cuidador
class Historial
{
    private array $mementos = [];
    private EditorTexto $editor;

    public function __construct(EditorTexto $editor)
    {
        $this->editor = $editor;
    }

    public function backup(): void
    {
        $this->mementos[] = $this->editor->guardar();
    }

    public function deshacer(): void
    {
        if (empty($this->mementos)) {
            echo "⚠️ No hay nada que deshacer.\n";
            return;
        }

        $memento = array_pop($this->mementos);
        $this->editor->restaurar($memento);
    }
}

// 🔹 4. Uso
$editor = new EditorTexto();
$historial = new Historial($editor);

$editor->escribir("Hola");
$historial->backup(); // Guardamos "Hola"

$editor->escribir(" Mundo");
$historial->backup(); // Guardamos "Hola Mundo"

$editor->escribir(" Cruel");
// Contenido: "Hola Mundo Cruel"

echo "\n--- Ups, me arrepiento ---\n";
$historial->deshacer(); // Vuelve a "Hola Mundo"
$historial->deshacer(); // Vuelve a "Hola"

// 🖥️ Salida:
// 📝 Escrito: 'Hola'. Contenido actual: 'Hola'
// 💾 Guardando estado...
// 📝 Escrito: ' Mundo'. Contenido actual: 'Hola Mundo'
// 💾 Guardando estado...
// 📝 Escrito: ' Cruel'. Contenido actual: 'Hola Mundo Cruel'
//
// --- Ups, me arrepiento ---
// ↩️ Restaurado a: 'Hola Mundo'
// ↩️ Restaurado a: 'Hola'

EA, ¡saluditos y nos vemos en los bares! 🍻