We are now at the second video of the section momento design pattern in the previous video.
We looked at the template design pattern in this video.
We will develop a simple example using a string as the state.
We want to save.
Us now look at a pattern with a fancy name.
If we check a dictionary to see the meaning of Memento we will find the description an object kept as
a reminder of a person or event here the keyword is reminder as we will remember actions with this design
pattern.
The meaning of Memento is very similar to the functionality it provides in design patterns.
Basically we have a type.
With some state and we want to be able to save milestones of its state having a finite amount of state
saved we can recover them if necessary for a variety of tasks undo operations historic and so on the
momentum design pattern usually has three players which are usually called actors.
The first one is Memento which is a type that stores the type we want to save.
Usually we won't store the business type directly and we provide an extra layer of abstraction through
this type.
Next one is the originator a type that is in charge of creating mementos and storing the current active
state.
We said that the memento type wrap states of the business type and we use the originator as the creator
of mementos.
And the third one is caretaker which is the type that stores the list of mementos that can have the
logic to store them in a database or not to store more than a specified number of them.
Memento is all about a sequence of actions over time say to undo one or two operations or to provide
some kind of transaction reality to some application.
Memento provides the foundations for many tasks but its main objective can be defined with these two
points.
First to capture an object state without modifying the object itself and next to save a limited number
of states so that we can retrieve them later.
We will develop a simple example using a string as the state we want to save.
This way we will focus on the common memento pattern implementations before making it a bit more complex
with a new example.
The String stored in a field of state instance will be modified and we will be able to undo the operations
done in this state.
We are constantly talking about state all in all the momento pattern is about storing and retrieving
states.
Our acceptance criteria must be all about states.
So we need to store a finite amount of states of type String and we also need a way to restore the current
stored state to one of the state list.
With these two simple requirements we can already start writing some tests for this example.
So let's start with the unit test.
As mentioned previously the momentum design pattern is usually composed of three actors state momento
and originator so we will need three types to represent these actors.
I've created a folder with the name Memento and here I have two files memento dot go and memento underscore
test dot go let's open momento dot go here we add the package name import F.M. T State type the state
type is the core business object we will be using during this example it's any kind of object that we
want to track now we add type momento the momento type has a field called state representing a single
value of state type our states will be containerized within this type before storing them in the caretaker
type you could be wondering why we don't just store directly state instances basically because it will
couple the originator and the caretaker to the business object and we want to have as little coupling
as possible it will also be less flexible as we will see in the second example.
Now let's add the originator type the originator type also stores a state the originator struct objects
will take states from mementos and create new mementos with their stored state the originator will have
two public methods the new memento method and the extract and store state method the new momento method
will return a new memento built with originator current state value the extract and store state method
will take the state of a momento and store it in the originators state field a question which toggles
here is what's the difference between the originator object and the momento pattern why don't we use
originator patterns object directly.
Well if the momento contains a specific state the originator type contains the state that is currently
loaded also to save the state of something could be as simple as to take some value or as complex as
to maintain the state of some distributed application next we add the caretaker type the caretaker type
stores the momento list with all the states we need to save it also stores an add method to insert a
new memento on the list and a memento retriever that takes an index on the memento list.
So let's start with the add method of the caretaker type the add method must take a memento object and
add it to the caretaker object list of mementos for now save this file and move to the memento test
dot go as I said before.
Let's add the add method of the caretaker type at the beginning of our test we created two basic actors
for momento the originator and the caretaker we set a first state on the originator with the description
idle then we create the first memento calling the new memento method this should wrap the current originator
state in a memento type our first check is very simple the state description of the returned memento
must be like the state description we pass to the originator that is the ideal description the last
step to check whether our mementos add method works correctly is to see whether the memento list has
grown after adding one item let's add the code for this logic we also have to test the memento into
method this should take a memento value from the caretaker list it takes the index you want to retrieve
from the list.
So as usual with lists we must check that it behaves correctly against negative numbers and out of index
values.
So now we add the test for caretaker momento.
We have to start like we did in our previous test creating an originator and caretaker objects and adding
the first momento to the caretaker.
Again we need to add a few lines of code for this.
Once we have the first object on the caretaker object we can ask for it using caretaker dot momento
0 index 0 on the momento into method retrieves the first item on the slice.
Remember that slices start with zero.
No error should be returned because we have already added a value to the caretaker object.
Then after retrieving the first memento we checked that the description matches the one that we passed
at the beginning of the test.
Now let's add a few more lines of code.
The last step on this test involves using a negative number to retrieve some value.
In this case an error must be returned that shows that no negative numbers can be used.
It is also possible to return the first index when you pass negative numbers.
But here we will return an error.
The last function to check is the extract and store state method.
This function must take a memento and extract all its state information to set it in the originator
object.
So let's add this last function to our code file.
This test is simple.
We create a default originator variable with an idle state.
Then we retrieve a new memento object to use it later.
We changed the state of the originator variable to the working state to ensure that the new state will
be written.
Finally we have to call the extract and store state method with the idle memento variable.
This should restore the state of the originator to the idle memento state's value something that we
checked in the last if statement.
Now it's time to run the tests save the file and open the terminal type of the command go test hyphen
V.
You can see that all the tests fail because the three tests fail.
We can continue with the implementation now the momento patterns implementation is usually very simple.
If you don't get too crazy the three actors memento originator and caretaker have a very defined role
in the pattern and their implementation is very straightforward.
Open the memento don't go file here.
We need to modify the originator function.
Done the originator object needs to return new values of momento types.
When calling the new memento method it also needs to store the value of a momento object in the state
field of the struct as needed for the extract and store state method let's make changes to the caretaker
add method and momento method the caretaker type is also straightforward when we call the add method
we overwrite the momento list field by calling the append method with the value past in the argument.
This creates a new list with the new value included when calling the momento method.
We have to do a couple of checks beforehand.
In this case we check that the index is not outside of the range of the slice and that the index is
not a negative number in the if statement in which case we return an error.
If everything goes fine it just returns the specified memento object and no errors.
Time to check the test results.
Save the file and open the terminal run the command go test hyphen V that was enough to reach 100 percent
of coverage.
While this is far from being a perfect metric at least we know that we are reaching every corner of
our source code and that we haven't cheated in our tests to achieve it.
Superb.
The previous example is good and simple enough to understand the functionality of the memento pattern.
However it is more commonly used in conjunction with the command pattern and a simple facade pattern.
The idea is to use a command pattern to encapsulate a set of different types of states.
Those that implement a command interface and provide a small facade to automate the insertion of the
caretaker object.
We are going to develop a small example of a hypothetical audio mixer.
We are going to use the same momento pattern to save two types of states volume and mute the volume
state is going to be a byte type and the mute state a boolean type.
We will use two completely different types to show the flexibility of this approach and its drawbacks
as a side note.
We can also shape each command interface with their own serialization methods on the interface.
This way we can give the ability to the caretaker to store states in some kind of storage without really
knowing what storing our command interface is going to have one method to return the value of its implementer.
It's very simple.
Every command in our audio mixer that we want to undo will have to implement this interface.
So let's open the momento underscore command not go file and add the command interface.
There is something interesting in this interface the Get value method returns an interface to a value.
This also means that the return type of this method is well on typed.
Not really but it returns an interface that can be a representation of any type.
And we will need to typecast it later if we want to use it specific type.
Now we have to define the volume and mute types and implement the command interface.
Let's do this.
Okay.
They are both quite easy implementations.
However the mute type will return a bull type on the Get value method and the volume will return a byte
type as in the previous example.
We'll need a momento type that will hold a command.
In other words it will store a pointer to a mute or a volume type.
So let's add type momento struct done the originator type works as in the previous example but uses
the command keyword instead of the state keyword.
Now let's add the originator struct the caretaker object is almost the same but this time we'll use
a stack instead of a simple list and we will store command instead of a state.
Let's add the lines of code for this however our momento list is replaced with a pop method.
It also returns a momento object but it will return them acting as a stack last to enter first to go
out so we take the last element on the stack and store it in the temporary memento variable.
Then we replace the stack with a new version that doesn't contain the last element on the next line.
Finally we return the memento variable.
Until now everything looks almost like in the previous example.
We also talked about automating some tasks by using the facade pattern.
Let's do it.
This is going to be called the momento facade type and we'll have the safe settings and restore settings
methods the safe settings method takes a command stores it in an inner originator and saves it in an
inner caretaker field.
The Restore settings method makes the opposite flow restores an index of the caretaker and returns the
command instead of the momento object.
So now we add the momento facade type our facade pattern will hold the contents of the originator and
the caretaker and will provide those too easy to use methods to save and restore settings.
So how do we use this.
Let's add the main function to use this.
First we get a variable with a facade pattern zero value initialization will give us zero valued originator
and caretaker object.
They don't have any unexpected field so everything will initialize correctly.
If any of them had a pointer for example it would be initialized to nil.
As we discussed in the video on zero initialization from the first section of our previous part go classical
patterns.
We create a volume value with volume 4.
And yes we have used parentheses the volume type does not have any in a field like struct so we cannot
use curly braces to set its value.
The way to set it is to use parentheses or create a pointer to the type volume and then set the value
of the pointed space.
We also save a value of the type mute using the facade pattern.
We don't know what command type is returned here so we need to make a type assertion.
We will make a small function to help us with this that checks the type and prints an appropriate value.
Let's add a cert and print function fine.
Now the assert and print method takes a command type and casts it to the two possible types.
That is volume or mute in each case it prints a message to the console with a personalized message.
Now let's continue and finish the main function.
So here's how our main function looks the part highlighted in bold shows the new changes within the
main function.
We took the index 0 from the caretaker object and passed it to the new function and the same with the
index one running this small program.
We should get the volume and mute values on the console.
Let's save the file and open the terminal and run the command.
Go run momento underscore command dot go right in this small example we have combined three different
design patterns to keep getting comfortable using various patterns.
Keep in mind that we could have abstracted the creation of volume and mute states to a factory pattern
too.
So this is not where you would stop with the momento pattern.
We have learned a powerful way to create undoable operations that are very useful when writing UI applications
but also when you have to develop transactional operations.
In any case the situation is the same.
You need a memento an originator and a caretaker actor.
A transaction operation is a set of atomic operations that must all be done or fail.
In other words if you have a transaction composed of five operations and just one of them fails the
transaction cannot be completed and every modification done by the other four must be undone in this
video.
We have explored about the memento design pattern in the next video.
We will dive into interpret her design pattern.