Java Reference
In-Depth Information
State within the
Memento
should be inaccessible to everybody except the
Originator
.
StateHolder -
The object that wishes to preserve the state. It never needs to know what is within a
Memento
; it
only needs to know that the object it receives enables it to restore the state of the
Originator
.
Because the
Memento
should be accessible only to the
Originator
, it is best to make the
Memento
a public inner
class in the
Originator
. All the methods are declared private so they are only available to the
Memento
and its
enclosing class, thus providing the appropriate encapsulation.
Instances of an inner class are always associated with an instance of the outer class. This is necessary because an
inner class always has access to instance variables of the outer class. That causes a problem in this situation; the
Memento
should be independent of a specific instance of an
Originator
. Therefore the
Memento
class needs to be
a static inner class.
Memento objects can become very large, especially if the
Originator
keeps all its state in the
Memento
and
Mementos
are created frequently. To compensate for this, you can change
Mementos
so that they record only
changes in state since the previous creation of a
Memento
. The state holder has to keep track of the order of the
Mementos
. Job promotions are an example of when you might apply this. After every promotion your employee
benefits and salary are changed based on the previous salary, and you may get a new boss, new department or a
bigger car. Now every
Memento
of your employee benefits only needs to record the increase or decrease in
conditions/salaries since the last
Memento
.
Benefits and Drawbacks
Using the Memento pattern has the following consequences.
Preserves encapsulation - Even when the state of the
Originator
needs to be stored outside of the
Originator
object in a client, the state is inaccessible to the client. It has a reference only to the
Memento
object, and no way
to access the information that's inside. It also makes the client simpler because it no longer needs to know
anything about the internal workings of the
Originator
, except how to get a
Memento
and how to use it.
Simpler
Originator -
Suppose the
Originator
has to keep track of all the different states. The
Originator
would soon become very bloated and very difficult to handle. It is much easier to give that responsibility to the
requesting party, the client. The
Originator
now only needs to be able to create and use
Mementos
instead of
keeping track of multiple states.
Expensive
Mementos -
Mementos
are very expensive to create if every piece of the
Originator's
state has to be
stored in the
Memento
. This increases dramatically as the
Originator
increases in size. This is where the
incremental changes are important. If the
Originator
is large,
Memento
might not be a suitable pattern.
Expensive
Memento
storage - The state holder is responsible for the life-cycle management after it receives the
Memento
from the
Originator
. However, it does not know how large the
Memento
actually is. If
Mementos
are
not kept as small as possible, the
StateHolder
will pay the price.
Pattern Variants
Pattern variants include the following:
If the Memento must be a standalone class, and not an inner class, you must define two interfaces:
WideMemento
and
NarrowMemento
. The wide interface is for the
Originator
of the
Memento
so that it can access the
Memento
to get its state. The state in the
Memento
is best set at construction time. Because you're defining an interface,
you'll need to add a
FactoryMethod
.
The narrow interface is intended for the
StateHolder
and other clients to use. If that interface doesn't have any
methods, the
NarrowMemento
becomes obsolete and the interested parties only refer to the
Memento
as an
Object
.
To be able to extend the
Originator
but not need to change the
Memento
code, the methods can have package
access instead of being private. This allows subclasses of the
Originator
to use the same
Memento
class.
Related Patterns
Related patterns include the following: