Showing posts with label Memento Design Pattern. Show all posts
Showing posts with label Memento Design Pattern. Show all posts

Wednesday, July 29, 2026

Memento Design Pattern

Mastering Design Patterns in C# and ASP.NET Core

Part 4.6 – Memento Design Pattern

Series: Design Patterns in C# and ASP.NET Core
Pattern Category: Behavioral Design Pattern
Difficulty: ⭐⭐⭐☆☆ Intermediate
Prerequisites: C#, OOP, Classes, Interfaces, Encapsulation, Dependency Injection, ASP.NET Core


Table of Contents

  1. Introduction

  2. What is the Memento Design Pattern?

  3. Why Do We Need the Memento Pattern?

  4. The Problem with Restoring Object State

  5. Memento Pattern Solution

  6. Originator, Memento, and Caretaker

  7. UML Class Diagram

  8. How the Memento Pattern Works

  9. Complete C# Console Application

  10. Undo/Redo Example

  11. Immutable Memento

  12. ASP.NET Core Implementation

  13. Banking Transaction Example

  14. Document Version History Example

  15. Configuration Snapshot Example

  16. Database Transaction and Memento

  17. Memento vs Command

  18. Memento vs Prototype

  19. Memento vs Snapshot

  20. Advantages

  21. Disadvantages

  22. Best Practices

  23. Common Mistakes

  24. Real-World Enterprise Scenarios

  25. Interview Questions

  26. Key Takeaways

  27. Conclusion

  28. Coming Up Next


1. Introduction

Applications frequently need the ability to save an object's state and restore it later.

For example:

  • A text editor needs Undo.

  • A drawing application needs previous versions.

  • A configuration system may need rollback.

  • A workflow engine may need to restore a previous state.

  • A game needs save points.

  • A banking application may need to preserve transaction state.

  • An application may need to maintain document versions.

Consider a document editor:

Document State
     ↓
Version 1
     ↓
Version 2
     ↓
Version 3
     ↓
Undo
     ↓
Restore Version 2

How can we save the previous state without exposing the internal implementation of the object?

This is where the Memento Design Pattern becomes useful.


2. What is the Memento Design Pattern?

The Memento Design Pattern is a behavioral design pattern that allows an object to capture and restore its previous state without exposing its internal implementation details.

The key idea is:

Capture an object's state at a particular point in time so that it can be restored later.

A simplified representation is:

Object
  ↓
Create Snapshot
  ↓
Memento
  ↓
Store
  ↓
Restore Later

The object whose state is saved is called the Originator.

The saved state is represented by a Memento.

The object that stores the mementos is called the Caretaker.


3. Why Do We Need the Memento Pattern?

Suppose we have:

public class Document
{
    public string Title { get; set; }

    public string Content { get; set; }

    public string Font { get; set; }
}

Now imagine that we want to implement:

Edit
Edit
Edit
Undo
Undo
Redo

One approach might be to expose all properties publicly and allow another class to copy them.

But this can lead to problems.

The caretaker may become tightly coupled to the internal structure of Document.

For example:

var title = document.Title;
var content = document.Content;
var font = document.Font;

Later, suppose we add:

public string BackgroundColor { get; set; }

Now every state-saving component may need to change.

This violates encapsulation.

The Memento Pattern provides a better abstraction.


4. The Problem with Restoring Object State

Consider a complex object:

Order
 ├── Customer
 ├── Items
 ├── Payment
 ├── Shipping
 ├── Discount
 └── Status

Saving and restoring the complete state manually can become complicated.

We don't want external classes to understand every internal detail.

Ideally:

Caretaker
   |
   | "Save"
   ↓
Originator
   |
   ↓
Memento

The caretaker stores the snapshot but does not need to understand its internal details.


5. Memento Pattern Solution

The Memento Pattern introduces three major components:

Originator
    |
    | creates
    ↓
 Memento
    ↑
    |
Caretaker

Originator

The object whose state needs to be saved.

Memento

Stores the state of the Originator.

Caretaker

Stores and manages Mementos.


6. Originator, Memento, and Caretaker

6.1 Originator

The Originator:

  • Maintains current state.

  • Creates a Memento.

  • Restores state from a Memento.

Example:

public class Document
{
    public string Content { get; private set; }

    public Memento Save()
    {
        return new Memento(Content);
    }

    public void Restore(Memento memento)
    {
        Content = memento.Content;
    }
}

6.2 Memento

The Memento stores a snapshot.

public class Memento
{
    public string Content { get; }

    public Memento(string content)
    {
        Content = content;
    }
}

6.3 Caretaker

The Caretaker stores snapshots.

public class History
{
    private readonly Stack<Memento> _history = new();

    public void Save(Memento memento)
    {
        _history.Push(memento);
    }

    public Memento Undo()
    {
        return _history.Pop();
    }
}

The important point is that the Caretaker doesn't modify the document's internal state directly.


7. UML Class Diagram

The classic UML structure looks like this:

                 +------------------+
                 |    Originator    |
                 +------------------+
                 | - state          |
                 +------------------+
                 | + Save()         |
                 | + Restore()      |
                 +--------+---------+
                          |
                          | creates
                          ↓
                 +------------------+
                 |     Memento      |
                 +------------------+
                 | - state          |
                 +------------------+
                 | + State          |
                 +------------------+
                          ↑
                          |
                          | stores
                 +--------+---------+
                 |    Caretaker     |
                 +------------------+
                 | - history        |
                 +------------------+
                 | + Save()         |
                 | + Undo()         |
                 +------------------+

8. How the Memento Pattern Works

Suppose a document has the following states.

State 1
Content = "Hello"

Save it:

Document
   ↓
Memento 1

Change it:

State 2
Content = "Hello World"

Save again:

Document
   ↓
Memento 2

Change again:

State 3
Content = "Hello World!"

Now the history contains:

History
 ├── Memento 2
 └── Memento 1

If the user chooses Undo:

Current State
     ↓
Restore Memento 2
     ↓
"Hello World"

9. Complete C# Console Application

Let's create a simple document editor.

Step 1 – Memento

public class DocumentMemento
{
    public string Content { get; }

    public DocumentMemento(string content)
    {
        Content = content;
    }
}

Step 2 – Originator

public class Document
{
    public string Content { get; private set; } = string.Empty;

    public void Write(string text)
    {
        Content += text;
    }

    public DocumentMemento Save()
    {
        return new DocumentMemento(Content);
    }

    public void Restore(DocumentMemento memento)
    {
        Content = memento.Content;
    }

    public void Show()
    {
        Console.WriteLine($"Document: {Content}");
    }
}

Step 3 – Caretaker

public class DocumentHistory
{
    private readonly Stack<DocumentMemento> _history = new();

    public void Save(DocumentMemento memento)
    {
        _history.Push(memento);
    }

    public DocumentMemento? Undo()
    {
        if (_history.Count == 0)
        {
            return null;
        }

        return _history.Pop();
    }
}

Step 4 – Program

var document = new Document();
var history = new DocumentHistory();

document.Write("Hello");
history.Save(document.Save());

document.Write(" World");
history.Save(document.Save());

document.Write("!");
document.Show();

var previousState = history.Undo();

if (previousState != null)
{
    document.Restore(previousState);
}

document.Show();

previousState = history.Undo();

if (previousState != null)
{
    document.Restore(previousState);
}

document.Show();

Output:

Document: Hello World!
Document: Hello World
Document: Hello

The flow is:

Write "Hello"
    ↓
Save
    ↓
Write " World"
    ↓
Save
    ↓
Write "!"
    ↓
Undo
    ↓
"Hello World"
    ↓
Undo
    ↓
"Hello"

10. Implementing Undo/Redo

A single stack is sufficient for Undo.

For both Undo and Redo, we typically need two stacks:

Undo Stack
Redo Stack

Conceptually:

             Current State
                  |
        +---------+---------+
        |                   |
    Undo Stack          Redo Stack

When the user changes the document:

Current
   ↓
Undo Stack

When Undo is performed:

Undo Stack
   ↓
Current
   ↓
Redo Stack

When Redo is performed:

Redo Stack
   ↓
Current
   ↓
Undo Stack

Complete Undo/Redo Example

public class DocumentHistory
{
    private readonly Stack<DocumentMemento> _undo = new();
    private readonly Stack<DocumentMemento> _redo = new();

    public void Save(DocumentMemento memento)
    {
        _undo.Push(memento);
        _redo.Clear();
    }

    public DocumentMemento? Undo(
        DocumentMemento current)
    {
        if (_undo.Count == 0)
        {
            return null;
        }

        _redo.Push(current);

        return _undo.Pop();
    }

    public DocumentMemento? Redo(
        DocumentMemento current)
    {
        if (_redo.Count == 0)
        {
            return null;
        }

        _undo.Push(current);

        return _redo.Pop();
    }
}

The important concept is:

New Change
   ↓
Clear Redo History

This is standard undo/redo behavior.


11. Immutable Memento

A Memento should ideally be immutable.

For example:

public sealed class DocumentMemento
{
    public string Content { get; }

    public DocumentMemento(string content)
    {
        Content = content;
    }
}

External code cannot change:

memento.Content

after construction.

This makes the snapshot safer and more predictable.


12. Using C# Records for Memento

Modern C# provides a convenient option using record.

public record DocumentMemento(
    string Content);

The Originator can create it:

public DocumentMemento Save()
{
    return new DocumentMemento(Content);
}

This is concise and works well when the snapshot is primarily data.


13. ASP.NET Core Implementation

Let's build a simplified document versioning API.

Suppose the API provides:

POST /api/documents
PUT  /api/documents/{id}
POST /api/documents/{id}/undo
GET  /api/documents/{id}

We can use a Memento-like snapshot model.


14. Document Model

public class Document
{
    public int Id { get; set; }

    public string Title { get; set; } = string.Empty;

    public string Content { get; set; } = string.Empty;
}

15. Document Snapshot

public record DocumentSnapshot(
    int Id,
    string Title,
    string Content);

This snapshot represents a point-in-time state.


16. Document Service

public interface IDocumentService
{
    Document Get(int id);

    void Update(
        int id,
        string title,
        string content);

    void Undo(int id);
}

Implementation:

public class DocumentService : IDocumentService
{
    private readonly Dictionary<int, Document> _documents = new();

    private readonly Dictionary<
        int,
        Stack<DocumentSnapshot>> _history = new();

    public Document Get(int id)
    {
        return _documents[id];
    }

    public void Update(
        int id,
        string title,
        string content)
    {
        var document = _documents[id];

        if (!_history.ContainsKey(id))
        {
            _history[id] =
                new Stack<DocumentSnapshot>();
        }

        _history[id].Push(
            new DocumentSnapshot(
                document.Id,
                document.Title,
                document.Content));

        document.Title = title;
        document.Content = content;
    }

    public void Undo(int id)
    {
        if (!_history.ContainsKey(id) ||
            _history[id].Count == 0)
        {
            return;
        }

        var snapshot = _history[id].Pop();

        var document = _documents[id];

        document.Title = snapshot.Title;
        document.Content = snapshot.Content;
    }
}

This is a simplified in-memory example.

In a production system, snapshots would generally need appropriate persistence and concurrency handling.


17. ASP.NET Core Controller

[ApiController]
[Route("api/documents")]
public class DocumentsController : ControllerBase
{
    private readonly IDocumentService _service;

    public DocumentsController(
        IDocumentService service)
    {
        _service = service;
    }

    [HttpGet("{id}")]
    public IActionResult Get(int id)
    {
        var document = _service.Get(id);

        return Ok(document);
    }

    [HttpPost("{id}/undo")]
    public IActionResult Undo(int id)
    {
        _service.Undo(id);

        return Ok(new
        {
            Message = "Document restored successfully."
        });
    }
}

The controller doesn't need to know how snapshots are managed.


18. Register the Service

In Program.cs:

builder.Services.AddSingleton<IDocumentService,
                              DocumentService>();

For a real database-backed implementation, the lifetime and persistence strategy should be designed according to the application's requirements rather than blindly using Singleton.


19. Banking Transaction Example

The Memento Pattern can be useful when an application needs to capture a business object's state before performing a change.

Consider:

Bank Account
     |
     +-- Balance
     +-- Status
     +-- Account Type

Before a complex operation:

Account State
     ↓
Create Snapshot
     ↓
Perform Operation

If the operation needs to be reversed at the application level:

Snapshot
    ↓
Restore

For example:

public record AccountMemento(
    decimal Balance,
    string Status);

Originator:

public class BankAccount
{
    public decimal Balance { get; private set; }

    public string Status { get; private set; }
        = "Active";

    public AccountMemento Save()
    {
        return new AccountMemento(
            Balance,
            Status);
    }

    public void Restore(
        AccountMemento memento)
    {
        Balance = memento.Balance;
        Status = memento.Status;
    }

    public void Deposit(decimal amount)
    {
        Balance += amount;
    }
}

The pattern can preserve application-level state.

However, it is important to distinguish this from a database transaction.


20. Memento vs Database Transaction

These concepts are not interchangeable.

Memento

Used to preserve and restore object/application state.

Object
 ↓
Snapshot
 ↓
Restore

Database Transaction

Used to ensure atomic database operations.

BEGIN TRANSACTION
     ↓
UPDATE
     ↓
INSERT
     ↓
COMMIT

If something fails:

ROLLBACK

Therefore:

Use database transactions for database atomicity and Memento when you need application-level state snapshots.


21. Document Version History

One of the best real-world examples is document versioning.

Suppose:

Document
Version 1
Version 2
Version 3
Version 4

The application can store snapshots:

Version 1 → Snapshot
Version 2 → Snapshot
Version 3 → Snapshot
Version 4 → Current

The user can then restore an earlier version.

This concept appears in many applications involving:

  • Documents

  • Configuration

  • Templates

  • Content management

  • Workflow definitions


22. Configuration Snapshot Example

Imagine an application configuration:

public class ApplicationSettings
{
    public int MaxRetries { get; set; }

    public int TimeoutSeconds { get; set; }

    public bool EnableFeatureX { get; set; }
}

Before changing configuration:

Current Configuration
        ↓
Create Snapshot
        ↓
Apply New Configuration

If the new configuration causes problems:

Snapshot
    ↓
Restore

This is useful in administrative systems where users can experiment with configuration changes.


23. Memento and Serialization

Sometimes snapshots are persisted as:

JSON
XML
Binary
Database Records

For example:

public record ConfigurationMemento(
    int MaxRetries,
    int TimeoutSeconds,
    bool EnableFeatureX);

The snapshot could be serialized into a persistence store.

However, if the state is large, storing complete snapshots for every change can become expensive.

That leads to an important design consideration:

Memento trades memory/storage for simpler state restoration.


24. Large Object State and Memory Considerations

Suppose an application creates:

1,000 snapshots

and each snapshot is:

5 MB

The storage requirement could become significant.

Therefore, Memento should be carefully designed for large objects.

Possible alternatives include:

  • Store only changed properties.

  • Store version identifiers.

  • Use database versioning.

  • Use event sourcing.

  • Store compressed snapshots.

  • Limit history size.


25. Memento vs Command

These patterns are frequently used together.

Command

Represents an operation:

DeleteDocumentCommand
UpdateOrderCommand
ChangeAddressCommand

Memento

Stores state:

Before State
After State

They can work together for Undo.

Command
   ↓
Execute
   ↓
Memento
   ↓
Undo

For example:

UpdateDocumentCommand
        ↓
Save Memento
        ↓
Update Document
        ↓
Execute

Undo:

Memento
   ↓
Restore

26. Memento vs Prototype

Both involve copying state, but they have different purposes.

MementoPrototype
Saves state for later restorationCreates new objects by cloning
Primarily supports undo/rollbackPrimarily supports object creation
Behavioral patternCreational pattern
Focuses on state historyFocuses on object creation

Memento:

Object
 ↓
Snapshot
 ↓
Restore

Prototype:

Existing Object
 ↓
Clone
 ↓
New Object

27. Memento vs Snapshot

The word "snapshot" is often used informally for the state stored by a Memento.

However, the design pattern provides a broader structure:

Originator
    ↓
Memento
    ↓
Caretaker

A snapshot can simply mean a saved representation of state.

Memento is specifically about encapsulating an object's state so it can be restored later without exposing its internals.


28. Advantages of Memento Pattern

1. Preserves Encapsulation

The Caretaker doesn't need to know the internal implementation of the Originator.


2. Supports Undo

One of the most common applications.

Edit
 ↓
Save
 ↓
Edit
 ↓
Undo

3. Supports Version History

Multiple states can be stored.

Version 1
Version 2
Version 3
Version 4

4. Simplifies State Restoration

The Originator itself knows how to restore its state.


5. Works Well with Immutable Snapshots

C# records and immutable objects make Memento implementations safer.


6. Separates State Management

The Caretaker can manage history without understanding business internals.


29. Disadvantages of Memento Pattern

1. Memory Usage

Multiple snapshots can consume significant memory.


2. Storage Requirements

Persistent version history can require substantial database storage.


3. Performance

Creating snapshots of large objects can be expensive.


4. Complex Object Graphs

If an object contains nested objects:

Order
 ├── Customer
 ├── Items
 │    ├── Product
 │    └── Product
 └── Payment

creating a safe snapshot may require careful deep-copy logic.


5. Version Compatibility

If snapshots are persisted for a long time, changes to the object model can make older snapshots difficult to restore.


30. Best Practices

1. Prefer Immutable Mementos

Use:

public record DocumentMemento(
    string Content);

where appropriate.


2. Keep Memento Creation Inside the Originator

Prefer:

document.Save();

instead of allowing external classes to manually copy every field.


3. Don't Expose Internal State Unnecessarily

The Caretaker should not need to manipulate the Originator's fields.


4. Limit History Size

For example:

private const int MaxHistory = 50;

This prevents unbounded memory growth.


5. Consider Deep Copy Carefully

If the state contains mutable objects, simply copying references can create unexpected behavior.


6. Use Database Versioning for Persistent History

If version history must survive application restarts, storing snapshots in memory is insufficient.


7. Consider Differential Snapshots

Instead of saving the entire object every time:

Version 1 → Full Snapshot
Version 2 → Changes only
Version 3 → Changes only

This can reduce storage requirements.


31. Common Mistakes

Mistake 1 – Using Shallow Copies Accidentally

Consider:

public class Order
{
    public List<OrderItem> Items { get; set; }
}

Copying the Order object without copying the list and its elements can leave multiple versions sharing the same mutable objects.

For state restoration, this can cause bugs.


Mistake 2 – Storing Mutable Mementos

A memento should represent a stable point-in-time state.

Prefer immutable state.


Mistake 3 – Unlimited History

This can eventually consume a large amount of memory.


Mistake 4 – Using Memento Instead of Transactions

Memento does not replace database transactions.


Mistake 5 – Saving Huge Objects Too Frequently

For example:

10 MB object
+
1000 snapshots
=
10 GB

This is a simplified example, but it illustrates why snapshot size and history limits matter.


Mistake 6 – Exposing All State to the Caretaker

If the caretaker understands every field, encapsulation has effectively been lost.


32. Real-World Enterprise Scenarios

The Memento Pattern can be useful for:

Document Management

Document
 ↓
Version
 ↓
Restore

Configuration Management

Configuration
 ↓
Snapshot
 ↓
Apply Change
 ↓
Rollback

Workflow Systems

Workflow State
 ↓
Snapshot
 ↓
Continue
 ↓
Restore

Game Development

Game State
 ↓
Save Point
 ↓
Continue

Drawing Applications

Canvas
 ↓
Snapshot
 ↓
Edit
 ↓
Undo

Form Editors

Form State
 ↓
Save
 ↓
Modify
 ↓
Undo

Business Applications

Business Object
 ↓
Snapshot
 ↓
Business Operation
 ↓
Restore

33. Memento in Enterprise Architecture

A simplified architecture might look like:

                    API
                     |
                     ↓
                Application
                     |
                     ↓
                Domain Object
                     |
               +-----+-----+
               |           |
             Save        Restore
               |           |
               ↓           ↓
            Memento ←→ History
               |
               ↓
        Persistence Store

This approach can be particularly useful when an application requires explicit state/version management.


34. Memento with Dependency Injection

Memento itself doesn't require dependency injection.

However, in ASP.NET Core, a history or snapshot repository can be injected.

For example:

public interface IDocumentHistoryRepository
{
    Task SaveAsync(
        int documentId,
        DocumentSnapshot snapshot);

    Task<DocumentSnapshot?> GetPreviousAsync(
        int documentId);
}

Implementation:

public class DocumentHistoryRepository
    : IDocumentHistoryRepository
{
    public Task SaveAsync(
        int documentId,
        DocumentSnapshot snapshot)
    {
        // Save snapshot to database

        return Task.CompletedTask;
    }

    public Task<DocumentSnapshot?> GetPreviousAsync(
        int documentId)
    {
        // Retrieve previous snapshot

        return Task.FromResult<DocumentSnapshot?>(
            null);
    }
}

The application service can then use the repository.


35. Memento and Clean Architecture

Memento can fit naturally into a Clean Architecture solution.

For example:

MyApplication
│
├── API
│
├── Application
│   ├── Commands
│   ├── Queries
│   └── Services
│
├── Domain
│   ├── Entities
│   ├── ValueObjects
│   └── Mementos
│
└── Infrastructure
    ├── Persistence
    └── Repositories

The exact placement depends on whether the snapshot is considered domain state, application state, or infrastructure persistence.


36. Interview Questions

Beginner

1. What is the Memento Design Pattern?

It is a behavioral pattern that allows an object to save and restore its previous state without exposing its internal implementation.


2. What are the three major components?

Originator
Memento
Caretaker

3. What is an Originator?

The object whose state needs to be saved and restored.


4. What is a Memento?

An object that stores a snapshot of the Originator's state.


5. What is a Caretaker?

An object responsible for storing and managing Mementos.


Intermediate

6. Where is Memento commonly used?

Examples include:

  • Undo/Redo

  • Document versioning

  • Configuration rollback

  • Game save points

  • Workflow state restoration


7. How does Memento preserve encapsulation?

The Originator creates and restores its own state. The Caretaker stores the Memento without needing to know the internal representation of the Originator.


8. What is the relationship between Memento and Undo?

Memento provides the saved state required to restore the object to an earlier state.


9. What is the difference between Memento and Prototype?

Memento preserves state for restoration.

Prototype clones an existing object to create another object.


10. Can Memento support Redo?

Yes.

A common implementation uses:

Undo Stack
Redo Stack

37. Advanced Interview Questions

11. What are the disadvantages of Memento?

The primary concerns are:

  • Memory usage

  • Storage requirements

  • Snapshot creation cost

  • Deep-copy complexity

  • Version compatibility


12. Does Memento replace database transactions?

No.

Memento manages application/object state.

Database transactions provide atomicity and consistency for database operations.


13. What happens if the object contains mutable collections?

A shallow copy may preserve references to the same collection, causing multiple states to share mutable data.

A suitable deep-copy or immutable-state strategy may be required.


14. How would you optimize Memento for large objects?

Possible approaches include:

  • Differential snapshots

  • Compression

  • Version identifiers

  • Limited history

  • Persistent snapshots

  • Event sourcing

  • Periodic full snapshots with incremental changes


15. Why should a Memento ideally be immutable?

Because a snapshot should represent a stable point-in-time state.

If the snapshot can change after being stored, history becomes unpredictable.


16. How would you implement Memento in ASP.NET Core?

Possible approaches include:

Domain Object
     ↓
Create Snapshot
     ↓
Application Service
     ↓
Snapshot Repository
     ↓
Database

17. How does Memento relate to Event Sourcing?

Both can preserve historical state, but they work differently.

Memento typically stores snapshots.

Event Sourcing stores the sequence of events that caused state changes.

They can also be combined.


18. When would you choose Event Sourcing instead of Memento?

If the application needs a complete, auditable history of business events, Event Sourcing may be more appropriate.

If the main requirement is simply restoring previous object state, Memento may be simpler.


38. Memento vs Event Sourcing

This distinction is especially important in enterprise applications.

Memento

State 1
State 2
State 3

The system stores snapshots.

Event Sourcing

AccountCreated
MoneyDeposited
MoneyWithdrawn
AddressChanged

The system stores events.

Current state can be reconstructed by replaying events.

Therefore:

Memento
→ Save state

Event Sourcing
→ Save changes/events

39. Practical Example – Document Editor

Let's put everything together.

Suppose a user writes:

Hello

The application saves:

Memento 1

User changes it:

Hello World

Save:

Memento 2

User changes it:

Hello World!

Current state:

Hello World!

The user presses Undo.

Current
Hello World!
      ↓
Restore
      ↓
Hello World

Press Undo again:

Hello World
      ↓
Restore
      ↓
Hello

This is the fundamental idea behind Memento.


40. Key Takeaways

Remember these important points:

1. Memento is a Behavioral Design Pattern

It focuses on managing and restoring object state.

2. It has three major components

Originator
Memento
Caretaker

3. Originator owns the state

It creates and restores Mementos.

4. Caretaker manages history

It stores snapshots without understanding their internal details.

5. Memento supports Undo/Redo

Two stacks are commonly used:

Undo
Redo

6. Prefer immutable snapshots

C# records are often convenient for snapshot data.

7. Watch memory usage

Large snapshots and unlimited history can be expensive.

8. Memento doesn't replace transactions

Use database transactions for database atomicity.

9. Memento and Event Sourcing are different

Memento stores state snapshots.

Event Sourcing stores events.

10. Use it when state restoration is a real requirement

Don't introduce Memento merely because it is a design pattern.


Conclusion

The Memento Design Pattern provides a clean way to preserve and restore an object's state while keeping the object's internal implementation encapsulated.

The fundamental architecture is:

                Originator
                   |
                   | Save()
                   ↓
                Memento
                   ↑
                   |
               Caretaker
                   |
                   | Restore()
                   ↓
                Originator

Its most common applications include:

  • Undo/Redo

  • Document versioning

  • Configuration rollback

  • Workflow restoration

  • Game save points

  • State snapshots

  • Application-level rollback

In modern C#, immutable records make snapshot objects particularly convenient:

public record DocumentMemento(
    string Content);

And in enterprise ASP.NET Core applications, Memento can be combined with:

ASP.NET Core
      ↓
Clean Architecture
      ↓
Application Services
      ↓
Domain Objects
      ↓
Memento / Snapshots
      ↓
Persistence

The most important lesson is:

Memento allows an object to preserve a point-in-time snapshot of its state and restore that state later without exposing the object's internal implementation details.

When used carefully, it provides an elegant foundation for undo/redo, versioning, and state restoration. However, for large or persistent histories, developers should consider storage costs, immutable snapshots, differential snapshots, database versioning, or Event Sourcing.


🚀 Coming Up Next: Part 4.7 – Observer Design Pattern

In the next article, we'll explore the Observer Design Pattern, including:

  • What is the Observer Pattern?

  • Why do we need it?

  • Subject and Observer concepts

  • One-to-many dependency

  • UML Class Diagram

  • Complete C# Console Application

  • Events and Delegates in C#

  • IObservable<T> and IObserver<T>

  • ASP.NET Core implementation

  • Event-driven architecture

  • Notification systems

  • Stock price monitoring

  • Banking transaction notifications

  • Order status notifications

  • Real-world enterprise scenarios

  • Advantages and disadvantages

  • Best practices

  • Common mistakes

  • Observer vs Mediator

  • Observer vs Pub/Sub

  • Observer vs Event-Driven Architecture

  • Interview questions

The Observer Pattern is especially important in modern .NET development because it provides the conceptual foundation for C# events, notifications, reactive programming, UI updates, and event-driven systems.

Don't Copy

Protected by Copyscape Online Plagiarism Checker