Memento design pattern

Memento – обект, който служи само за да съхранява ЕДНА „моментна снимка“ (shapshot) на обект, който ще наричаме Originator.

И отделните Memento обекти („mementos“ на Originator обектът) могат от своя страна да бъдат организирани като масив например, където да се трупат и достъпват.

A memento is an object that stores a snapshot of the internal state of another object—the memento’s originator.

Много важно е Memento класът да не допуска друг клас освен Originator да има достъп до отделните запазени състояния (snaphots), демек Originator-ът сам да си управлява така да се каже „миналите състояния“.

Също, класът Memento трябва да има поне една двойка публични сетър/гетър методи, които Orginator да вика, за да може да вземе текущото състояние на данните на Memento, както и да може да възстанови някои от предишните такива. Това ще са така да се каже „прозорци“ на Memento класа.
Да не забравяме, че принципите data hiding и capsulation трябва да се спазват.

Originator – това ще е обектът, на който ще запазваме отделните състояния.
Only the originator can store and retrieve information from the memento, the memento is „opaque“ to other objects.

Оригинаторът ще има един метод (напр. „saveToMemento()“), в който ще се създава обект Memento, на който пък се подава дадената информация (моментна снимка), която ще искаме да съхраним.
Ще има съответно и метод (напр. „restoreFromMemento()“), който ще приема даденото „мементо“, което искаме да възстановим.

CareTaker – това е класът, който ще използваме като „шкафче“ и където ще пазим отделните mementos, например като масив. Originator ще използва този клас за да добавя/извилича отделните mementos.

CareTaker не се интересува и не работи по никакъв начин с информацията, съхранена в него, само я съхранява, добавя и изважда от „шкафчето“ за да я върне на Originator.

Прост пример:

<?php
/**
 * Това ще ни е класът, на когото ще пазим отделните "моментни снимки" 
 * с оглед на това да можем да възстановяваме
 * когато ни трябва. Тоест, заради него ще прилагаме самият Memento Design Pattern.
 * Съществените методи са "saveToMemento()" и "restoreFromMemento()"
 */
class Originator
{
    private string $state;

    // The class could also contain additional data that is not part 
    // of the Memento Design Pattern

    public function set(string $state) : void
    {
        $this->state = $state;
        printf("%s\n\n", 'Originator: Setting state to ' . $state);
    }

    public function saveToMemento() : Memento
    {
        printf("%s\n\n", 'Originator: Saving to Memento.');
        return new Memento($this->state);
    }

    public function restoreFromMemento(Memento $memento) : void
    {
        $this->state = $memento->getSnapshot();
        printf("%s\n\n", 'Originator: State after restoring from Memento: ' . $this->state);
    }
}


/**
 * Този клас ще играе ролята на една прост data container, всеки обект 
 * от който ще е просто една "моментна снимка",
 * по този начин информацията ("моментната снимка") ще е "скрита" от 
 * околният свят (data hidding).
 */
class Memento
{
    private string $snapshot;

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

    public function getSnapshot() : string
    {
        return $this->snapshot;
    }
}


/**
 * Това ще е така да се каже "диригентът" на това да създаваме моментни снимки,
 * и да можем да ги възстановяваме.
 */
class Caretaker
{
    private array $savedStates = array();  // This will be the array with the mementos

    private Originator $originator;

    public function __construct(Originator $originator)
    {
        $this->originator = $originator;
    }

    public function takeCare() : void
    {
        $this->originator->set("State 1");

        $this->originator->set("State 2");

        // Push a memento, или още "Запази се себе си в едно Memento и го дай да го пушнем в $savedStates"
        array_push($this->savedStates, $this->originator->saveToMemento()); 

        $this->originator->set("State 3");

        $this->originator->set("State 4"); 

        // Push a memento, или още "Направи си селфи и ми го дай да го пушна в $savedStates" 
        array_push($this->savedStates, $this->originator->saveToMemento()); 

        $this->originator->set("State 5");

        $this->originator->restoreFromMemento($this->savedStates[1]);
    }
}

(new Caretaker(new Originator))->takeCare();