4

The GoF book "Design Patterns" describes the Memento pattern as an object encapsulating its state in a separate object. However, the book specifically describes the memento for use with a specific caretaker; in their example, a undo/redo provider.

However, this pattern, especially in C# when the Memento is made a struct (in both the technical and conceptual senses), can provide many benefits when made a more general part of a class:

  • Allow easy cloning, which makes caching, ect easier and less error prone
  • Allow persistence logic to be easily and gracefully shared by different versions of model which spans multiple domains
  • Display properties in a UI which would otherwise be encapsulated
  • Deal with CRUD operations for otherwise encapsulated properties
  • Dealing with scope envy when it is unavoidable, for example a class which governs an operation between two other classes (does a customer book a flight, or does a flight add a customer? Let's avoid this question by putting flight booking in a separate place)
  • We can use the convenient object intilizer syntax without making our properties editable. Also, we avoid constructors which are bloated with arguments
  • And of course, persistence of otherwise encapsulated properties

We can also use the memento as a kind of implicitly safe to serialize version of the class throughout the application.

However, you could argue, many of the above are just abusing the pattern for the purpose of circumventing language shortcomings.


For example:

public class Computer
{
     public Computer(ComputerMemento state)
     {
         _state = state;
     }

     private ComputerMemento _state;
     public ComputerMemento State
     {
         get
         {
              var copy = _state;
              return copy;
         }
     }

     public void DoSomeComputerThing() { }
     public void DoComputerStuff() { }
     public int GetSomeComputerCalculation() { }
}

public struct ComputerMomento
{
    public string MachineName;
    public float ProcessorSpeed;
    public long AmountOfRam;
    public int CPUCores;
}

The above Computer class can now expose an editable representation of its states while still being able to certify (albeit in an easily circumventable way) that changes to its state (via its methods) are valid and supported. Basically, the consumer can select its desired level of ignorance.

Is this expanded use of what seems to be the memento pattern still the memento pattern? If not, does it have a name?


EDIT: In the above code, since structs are passed by value, the state is immutable by outside classes.

6
  • close voter, please leave a comment with recommendation for improvement Jan 1, 2018 at 19:14
  • Your example seems far from the GoF Memento pattern to me. The ComputerMemento is modifiable, not just replaceable. Are you really asking about "name this pattern"? Or is there a more impactful question about the pitfalls of your approach?
    – joshp
    Jan 1, 2018 at 19:36
  • @joshp it is not modifiable. In C#, a struct is immutable Jan 2, 2018 at 14:12
  • @joshp I am really asking about name the pattern, but I would love to hear pitfalls too Jan 2, 2018 at 14:13
  • If C# structs are immutable then what is Eric Lippert talking about here stackoverflow.com/questions/3751911/…. And then there's this question: stackoverflow.com/questions/36780200/…. If it's immutable why does it have a private setter? Not trying to be disagreeable, here. I really just don't know the C# details. I would guess that an immutable struct in recent C# would have no setters for properties, or would have readonly fields.
    – joshp
    Jan 2, 2018 at 18:12

1 Answer 1

7

The memento pattern

The intent of the memento is clearly defined in GoF:

Without violating encapsulation, capture and externalize an object's internal state so that the object can be restored to this state later.

The key of that pattern is its dual interface: for the outside world the memento is a closed black-box that can be passed to whomever needs to receive (narrow interface), but only its originator is allowed to open it (wide interface).

The GoF implementation example uses C++ friend to implement the dual interface that ensures the respect of the encapsulation. In languages that to not provide this feature the memento could be implemented using two distinct interfaces.

Your pattern

Your "memento" exposes publicly the state. This breaks the encapsulation, and others than the originator may change this saved state. This is a significant divergence from the GoF memento.

In your design you fortunately make sure that the memento only allows valid changes. But this requires:

  • either a duplication of state control logic (both in Computer an ComputerMomento). For complex objects this could be a source of bugs;
  • or the use of the memnto's interface to change the object's internal state.

Additionally, you are no longer free to change the internal state as you want: suppose you'd decide that CPUCores would no longer be a stored value, but a value deduced from the CPUmodel. This would then require to change the memento interface and all the code that use the extended memento interface.

It's not a memento, but...

It appears that you use ComputerMomento both as internal state and as external copy of a previous state.

This looks very close to a simplified state pattern where a Computer would only have a single state. However, you don't have typical GoF state dependent behavior here, because all the behavior is implemented in the Computer.

So in the end you just used composition to isolate the internal state of a Computer from its behavior. From a naming perspective, IMHO it would be less ambiguous to call it ComputerState or ComputerConfiguration rather than ComputerMomento.

4
  • 2
    Nice answer. And i would like to make it +2 for having the energy to write it New Year's Day.
    – joshp
    Jan 1, 2018 at 23:07
  • @Christopher "This breaks the encapsulation, and others than the originator may change this saved state" In C# structs are immutable, so the state that the class is using cannot be changed, except by the class. Jan 2, 2018 at 14:15
  • @TheCatWhisperer thanks for this precision. So it's better than I feared. But even if not mutable, the internals are disclosed to the outside world. This might still reduce the level of freedom for changing the internals.
    – Christophe
    Jan 2, 2018 at 15:14
  • @Christophe not all the internals must necessarily be in the state object. And while there is truth to that... almost all of the software I've encountered in the wild exposes all its properties for mutation. This is done because many of the adjectives about a model need to be displayed to a user. Jan 2, 2018 at 15:47

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.