Click here to Skip to main content
15,867,834 members
Articles / Programming Languages / C#
Article

Mementos

Rate me:
Please Sign up or sign in to vote.
4.41/5 (13 votes)
2 Jun 20054 min read 54.4K   42   7
A basic IMemento implementation.

There is no download associated with this article. For some usage examples, check out:

Introduction

The IMemento interface is simple yet powerful. Classes that implement this interface can preserve and restore their state in any internal representation that they choose. Classes that interface to classes implementing IMemento can request that the instance save/restore its state without knowing the details of the save/restore mechanism. While this can deceive you into thinking that IMemento is a good way of managing persistent information, it is not. For that, the usual n-tiered pattern, which usually includes a data access layer, should be used. The IMemento is useful in storing localized state information regarding an object. This state information is disassociated with any other application information (as in, it does not have any relationship to any other information in the application).

Memento Design Pattern

The Memento design pattern is well known and you can read more about it here. The Eclipse project also has a good write-up on it here. One might not think that the Memento design pattern is worthy of an entire article, but I feel that it is such a useful pattern that it can stand on its own merits. Furthermore, this article describes extending the Memento design pattern to something that I think is more useable for real world applications. As the Memento design pattern stands, it is lacking some features.

The typical design pattern looks like this:

The reality is though, that one rarely uses a memento without also associating some contextual information about the memento. Why was the memento created? What did the user just do? What did the application just do? For this reason, I find it more useful to have the Memento object include an Action string:

If you read the documentation on the Memento design pattern, you'll notice that there is an "Originator" class that implements SetMemento and CreateMemento methods. For this mechanism to be truly useful, the class where you want to preserve/restore state information should ideally tell the application that it is capable of doing so, through its own interface, which I have called "ISupportMemento":

Now we have all the players on the stage--classes that support mementos always implement a standard interface mechanism, and the classes that implement the memento include some contextual information.

Interface Implementations

C#
public interface IMemento
{
  object State
  {
    get;
    set;
  }

  string Action
  {
    get;
    set;
  }
}

public interface ISupportMemento
{
  IMemento Memento
  {
    get;
    set;
  }
}

A Concrete Memento Class

If you don't have to deal with multiple inheritance issues, you can derive your specialized memento class from a concrete Memento class rather than an interface. Usually this should be the case, since the memento is managed by a separate class rather than the originator class. The basic implementation looks like this:

C#
public class Memento : IMemento
{
  protected object state;
  protected string action;

  public virtual object State
  {
    get {return state;}
    set {state=value;}
  }

  public string Action
  {
    get {return action;}
    set {action=value;}
  }
}

You will note that I am using properties instead of discrete GetState/SetState methods. Since the design patterns were originally written for C++, they don't always look like what you'd probably want to implement in C#. So, my actual IMemento interface looks like this, diagrammatically:

Who Manages State?

Note that there's quite a bit of flexibility with regards to which object creates the state information. I've illustrated two slightly different implementations. In this example, the class implementing ISupportMemento creates the state:

Example 1: Originator Creates The State Object

C#
public class MyClass : ISupportMemento
{
  public IMemento Memento
  {
    get
    {
      Memento mcm=new Memento();
      mcm.State=GetMyState();
      return mcm;
    }
    set
    {
      SetMyState(value.State);
    }
  
  protected object GetMyState()
  {
    // ... implementation ...
  }

  protected void SetMyState(object state)
  {
    // ... implementation ...
  }
}

In this example, the class implementing the IMemento creates the state.

Example 2: Memento Creates The State Object

C#
public class MyClass : ISupportMemento
{
  public IMemento Memento
  {
    get
    {
      IMemento mcm=new MyClassMemento(this);
      return mcm;
    }
    set
    {
      ((MyClassMemento)value).SetState(this);
    }
  }
}

public class MyClassMemento : Memento
{
  public MyClassMemento(MyClass mc)
  {
    // get MyClass state by querying properties of MyClass instance.
  }

  public void SetState(MyClass mc)
  {
    // set MyClass state by setting properties of MyClass instance.
  }
}

The advantage with the second implementation is that you can change the persistence mechanism without affecting the originator implementation--it is independent of the originator class. However, the implementation is a bit more complex and relies on casting the IMemento to the appropriate concrete memento implementer, which can be prone to error if the wrong instance is passed in.

Conclusion

I specifically wanted to avoid the topic of "how do you actually create the state?" There are many answers--maybe the state is a simple value. Maybe you want to use XML serialization, or binary serialization. In the first example, the originator has the smarts to persist itself. In the second example, you may want to decorate properties with an attribute that provides information about what properties should be persisted. You may want to include default values. So, as you can see, the issue of persistence is itself complex.

One final note--you'll find the memento pattern used frequently in undo/redo buffers, and this is why I've also included the Action contextual information in my IMemento implementation.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Architect Interacx
United States United States
Blog: https://marcclifton.wordpress.com/
Home Page: http://www.marcclifton.com
Research: http://www.higherorderprogramming.com/
GitHub: https://github.com/cliftonm

All my life I have been passionate about architecture / software design, as this is the cornerstone to a maintainable and extensible application. As such, I have enjoyed exploring some crazy ideas and discovering that they are not so crazy after all. I also love writing about my ideas and seeing the community response. As a consultant, I've enjoyed working in a wide range of industries such as aerospace, boatyard management, remote sensing, emergency services / data management, and casino operations. I've done a variety of pro-bono work non-profit organizations related to nature conservancy, drug recovery and women's health.

Comments and Discussions

 
GeneralThis is not Memento Pin
Frank Szendzielarz3-Nov-05 23:21
Frank Szendzielarz3-Nov-05 23:21 
GeneralRe: This is not Memento [modified] Pin
PunCha22-Nov-06 21:56
PunCha22-Nov-06 21:56 
GeneralMemento Strategy Pin
Bosah27-Jun-05 9:19
Bosah27-Jun-05 9:19 
GeneralPotential for casting exception in example 1 Pin
tommyv10-Jun-05 4:08
tommyv10-Jun-05 4:08 
GeneralMemento Hides State Pin
Samuel Ford7-Jun-05 1:13
Samuel Ford7-Jun-05 1:13 
GeneralPoint Pin
NormDroid2-Jun-05 21:32
professionalNormDroid2-Jun-05 21:32 
GeneralRe: Point Pin
Marc Clifton3-Jun-05 0:55
mvaMarc Clifton3-Jun-05 0:55 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.