Wzorzec projektowy Pamiątka - okładka

Wzorzec projektowy Pamiątka (Memento)

Opublikowano Kategorie Czysty kodCzas czytania 4min

Wzorzec projektowy Pamiątka (Memento) to jeden z behawioralnych wzorców projektowych opisanych przez Gang of Four. W tym artykule poznasz jego specyfikę oraz dowiesz się, kiedy warto go wykorzystać. Przykłady kodu w artykule przygotowane zostały w TypeScripcie.

Ten wpis jest kolejnym wpisem z serii o wzorcach projektowych. Jeśli chcesz poznać inne wzorce projektowe lub dowiedzieć się czym są wzorce projektowe, to koniecznie sprawdź mój wpis o wzorcach projektowych.

Wzorzec projektowy Pamiątka (Memento) w teorii

Intencją wzorca Pamiątka (Memento) jest zapisanie wewnętrznego stanu obiektu w formie zewnętrznego obiektu (snapshotu). Dzięki temu mamy możliwość późniejszego przywrócenia stanu obiektowi. Stan oryginalnego obiektu (Originator) zapisywany jest w obiekcie pamiątki. Pamiątkami zarządza Caretaker bez możliwości ingerencji w ich zawartość. Obiekty pamiątki nie powinny być modyfikowane po stworzeniu. Caretaker nie zna wewnętrznej struktury Pamiątki ani sposobu jej tworzenia czy interpretacji – zarządza jedynie ich kolekcją.

Dzięki wykorzystaniu Pamiątki nie ma również konieczności psucia hermetyzacji stanu Originatora. Bez wykorzystania Memento pozyskanie stanu wymagałoby upublicznienia stanu obiektu. W wielu przypadkach publiczny stan jest niepożądany.

Rozwiązywany problem może budzić skojarzenia z Event Sourcingiem. Jest to słuszne skojarzenie. Zarówno wzorzec Pamiątki, jak i event sourcing rozwiązują podobne problemy. Jednak sposób rozwiązania problemu w obu przypadkach jest istotnie różny.

Memento przechowuje pełen stan obiektu na dany moment. W przypadku Event Sourcingu do czynienia mamy z szeregiem zdarzeń. W przeciwieństwie do Memento Event Sourcing nie przechowuje pełnego stanu — jego rekonstrukcja może wymagać przetworzenia wszystkich zdarzeń. Memento nie wymusza tworzenia snapshotu po każdej zmianie. Event Sourcing przechowuje pełną historię zdarzeń, co pozwala na odtworzenie stanu z dowolnego miejsca w historii.

Diagram klas

Poniższy diagram przedstawia strukturę klas typową dla wzorca Pamiątki.

Wzorzec Pamiątka - okładka

Zastosowanie

Opis wzorca dość intuicyjnie pozwala znaleźć praktyczne przykłady jego wykorzystania. Z pewnością miałeś/aś okazję pracować z dowolnym programem do edycji plików z możliwością cofnięcia lub przywrócenia zmian. Jednym ze sposobów implementacji tego mechanizmu jest właśnie wzorzec Pamiątka.

Wzorzec Pamiątka znajdzie też zastosowanie w aplikacjach, które wymagają możliwości wykonania rollbacku. Przykładowo, możemy mieć aplikację pozwalającą na edycję szaty graficznej – np. rozmiaru i kroju czcionki, jednostek miary czy kolorystyki.

Wejście w ustawienia i wybranie konkretnej opcji natychmiastowo aplikuje zmiany, co pozwala użytkownikowi ocenić, czy dana konfiguracja mu odpowiada. Jednak zmiany te powinny zostać zapisane dopiero po ich zatwierdzeniu. W przypadku anulowania edycji chcemy cofnąć stan do tego sprzed rozpoczęcia zmian.

Aby to osiągnąć, możemy skorzystać ze wzorca Pamiątki. Przed rozpoczęciem edycji zapisujemy aktualną konfigurację jako Pamiątkę. Jeśli użytkownik kliknie „Anuluj”, przywracamy stan z Pamiątki.

Innym ciekawym przykładem praktycznego zastosowania jest zapisywanie i wczytywanie stanu gry. W takcie zapisu tworzony jest obiekt Pamiątki, a przy wczytywaniu jest aplikowany.

Praktyczny przykład

Przykład symuluje edytor tekstu z możliwością cofania zmian. Jest to przykład przewijający się w wielu materiałach. Jednak pozwala on w bardzo łatwy sposób zrozumieć jak w praktyce wykorzystać omawiany wzorzec. Dlatego również i ja z niego skorzystam.

Implementacja składa się z trzech klas:

  • TextDocument (Originator) –  zawiera stan dokumentu oraz wytwarzający Pamiątki. Stanem dokumentu jest jego tekstowa zawartość.
  • DocumentSnapshot (Memento) – przechowuje stan dokumentu z danej chwili. Zawartość dokumentu jest tylko do odczytu;
  • TextDocumentHistory (Caretaker) – przechowuje i udostępnia obiekty DocumentSnapshot;

class DocumentSnapshot {
  constructor( private readonly documentContent: string ) {}

  getContent(): string {
    return this.documentContent;
  }
}

class TextDocument {
  private _content: string = '';

  addContent( text: string ) {
    this._content += text;
  }

  getContent(): string {
    return this._content;
  }

  save(): DocumentSnapshot {
    return new DocumentSnapshot( this._content );
  }

  restore( snapshot: DocumentSnapshot ) {
    this._content = snapshot.getContent();
  }
}

class TextDocumentHistory {
  private history: DocumentSnapshot[] = [];

  addRevision( snapshot: DocumentSnapshot) {
    this.history.push( snapshot );
  }

  getLastRevision(): DocumentSnapshot | undefined {
    return this.history.pop();
  }
}

const editor = new TextDocument();
const textDocumentHistory = new TextDocumentHistory();

editor.addContent( 'Test content!' );
textDocumentHistory.addRevision( editor.save() );

editor.addContent( ' Incorrect content' );
console.log( editor.getContent() ); // Test content! Incorrect content

editor.restore( textDocumentHistory.getLastRevision()! );
console.log( editor.getContent() ); // Test content!

Podsumowanie

Jeśli masz jakiś ciekawy praktyczny przykład, gdzie udało Ci się wykorzystać Memento, to zachęcam do podzielenia się nim w komentarzu.

Książkę Design Patterns: Elements of Reusable Object-Oriented Software możesz kupić, klikając TEN link. Kupując z tego linku, wspierasz rozwój bloga.

Źródła i materiały dodatkowe

Dominik Szczepaniak

Zawodowo Senior Software Engineer w CKSource. Prywatnie bloger, fan włoskiej kuchni, miłośnik jazdy na rowerze i treningu siłowego.

Inne wpisy, które mogą Cię zainteresować

Przygotuj się lepiej do rozmowy o pracę!

Odbierz darmowy egzemplarz e-booka 106 Pytań Rekrutacyjnych Junior JavaScript Developer i realnie zwiększ swoje szanse na rozmowie rekrutacyjnej! Będziesz też otrzymywać wartościowe treści i powiadomienia o nowych wpisach na skrzynkę e-mail.

Dlaczego warto?

  • 👉 Ponad 1000 pobrań e-booka!
  • 👉 60 stron pełnych pytań i zadań praktycznych. Pytania i zadania pochodzą z faktycznych procesów rekrutacyjnych.

E-booka odbierzesz korzystając z formularza poniżej 👇

Okładka e-booka - Kolejna książka o Gicie

Subscribe
Powiadom o
guest

0 komentarzy
oceniany
najnowszy najstarszy
Inline Feedbacks
View all comments