Hello.
We are now at the last video of this section flyweight design pattern in the previous video.
We looked at facade design pattern in this video.
We learned to simulate things that we find on betting Web pages.
Also we will see how to store each team's information just once.
And we will deliver references to them to the users.
Our next pattern is the flyweight design pattern.
It's very commonly used in computer graphics and video game industry but not so much in enterprise applications
flyweight is a pattern which allows sharing the state of a heavy object between many instances of some
type.
Imagine that you have to create and store too many objects of some heavy type that are fundamentally
equal.
You'll run out of memory pretty quickly.
This problem can be easily solved with the fly weight pattern with additional help of the factory pattern.
The factory is usually in charge of encapsulating object creation as we saw previously thanks to the
fly weight pattern.
We can share all possible states of objects in a single common object and thus minimize object creation
by using pointers to already created objects to give an example.
We are going to simulate something that you find on betting Web pages.
Imagine the final match of the European Championship which is viewed by millions of people across the
continent.
Now imagine that we own a betting Web page where we provide historical information about every team
in Europe.
This is plenty of information which is usually stored in some distributed database and each team has
literally megabytes of information about their players matches.
Championships and so on.
If a million users access information about a team and a new instance of the information is created
for each user querying for historical data we will run out of memory in the blink of an eye with our
proxy solution.
We could make a cache of the end most recent searches to speed up queries but if we return a clone for
every team we will still get short on memory.
But faster thanks to our cash money right.
Instead we will store each team's information just once and we will deliver references to them to the
users.
So if we face a million users trying to access information about a match we will actually just have
two teams in memory with a million pointers to the same memory direction.
The acceptance criteria for a flyweight pattern must always reduce the amount of memory that is used
and must be focused primarily on this objective.
First we will create a team struct with basic information such as the team's name players historical
results and an image depicting their shield.
Next we must ensure a correct team creation.
Note the word creation here candidate for a creation or pattern and not having duplicates.
And secondly when creating the same team twice we must have two pointers pointing to the same memory
address.
Now let's move to the basic struct and tests our team struct will contain other struct inside so a total
of four struct will be created.
I have already two files flyweight dot go and flyweight underscore test dot go.
Let me open the flyweight dot go file now let me add the package name and the import statement.
Now we add the team struct it has the following signature.
Each team has an I.D. and name some image and a slice of bytes representing the teams shield a slice
of players and a slice of historical data.
This way we will have two teams I.D..
Now let's add constants.
We declare two constants by using the concept and iota keywords the concept keyword simply declares
that the following declarations are constants iota is on typed integer that automatically increments
its value for each new constant between the parentheses the IOTA value starts to reset to 0 when we
declare Team A.
So t may is equal to zero on the team B variable iota is incremented by 1.
So Team B is equal to 1 the IOTA assignment is an elegant way to save typing when declaring constant
values that doesn't need specific value like the PI constant on the math package.
Now let's add our player and historical data lets me align this properly cool as you can see we also
need a match struct which is stored within historical data struct a matched struct in this context represents
the historical result of a match.
Let's add the match struct this is enough to represent a team and to fulfil acceptance criteria 1 you've
already guessed that there is a lot of information on each team as some of the European teams have existed
for more than 100 years for acceptance criteria to the word creation should give us some clue about
how to approach this problem we will build a factory to create and store our teams our factory will
consist of a map of years including pointers to teams as values and a get team function using a map
will boost the team search if we know their names in advance we will also dispose of a method to return
the number of created objects which will be called to get number of objects.
Method so let's add this method.
This is enough to write our first unit test.
Let's save this file and go back to flyweight test.
Don't go and we add test function over here in our test we verify all the acceptance criteria.
First we create a factory and then ask for a pointer of Team A.
This pointer cannot be nil or the test will fail.
Then we call for a second pointed to the same team.
This pointer can't be nil either and it should point to the same memory address as the previous one.
So we know that it has not allocated a new memory.
Finally we should check whether the number of created teams is only 1 because we have asked for the
same team twice.
We have two pointers but just one instance of the team go to the terminal and now run the tests.
Well it failed.
Both pointers were nil and it has not created any object.
Interestingly the function that compares the two pointers doesn't fail all in all nil equals nil Now
let's move to implementation our get team method will need to scan the map field calls created teams
to make sure the query team is already created and return it.
If so if the team wasn't created it will have to create it and store it in the map before returning.
Let's go to our flyweight dot go file and we need to modify this code.
This code is very simple.
If the parameter name exists in the created teams map return the pointer.
Otherwise call a factory for Team creation.
This is interesting enough to stop for a second and analyze when you use the fly weight pattern.
It is very common to have a fly weight factory which uses other types of creation or patterns to retrieve
the objects it needs.
So the get team factory method will give us the team we are looking for.
We will store it in the map and return it.
The team factory will be able to create two teams team a and Team B.
Let's add the get team factory method with the switch statement.
We are simplifying the object's content so that we can focus on the fly weight patterns implementation.
Okay so we just have to define the function to retrieve the number of objects created which is done
as I show you.
We need to modify the return statement.
This was pretty easy.
The lend function returns the number of elements in an array or slice the number of characters in a
string and so on.
It seems that everything is done and we can launch our tests again save the file and move to the terminal
execute the command.
Go test hyphen v hyphen run equal to get team enter panic.
Have we forgotten something by reading the stack trace on the panic method we can see some addresses
some files and it seems that the get team method is trying to assign an entry to a nil map online seventy
one of the fly Wait don't go file let's look at line 71 closely.
And here is the line which we were searching for.
You can find it more easily with your editor.
Remember if you are writing code while following this tutorial that the error will probably be in a
different line so look closely at your own stock.
Trace okay this line is on the Get team method and when the method passes through here it means that
it had not found the team on the map that has created it.
The variable team and is trying to assign it to the map but the map is nil because we haven't initialized
it.
When creating the factory I'm sure you've seen the problem here already.
If we don't have access to the package we can initialize the variable Well we can make the variable
public and that's all.
But this would involve every implementer necessarily knowing that they have to initialize the map and
its signature is neither convenient or elegant.
Instead we are going to create a simple factory builder to do it for us.
This is a very common approach in go so let's build a new team factory.
Let's save this file and go to flyweight test.
Don't go now in the test.
We replace the factory creation with a call to this function save the file and move to the terminal.
Now let's run the test again.
Perfect.
Let's improve the test by adding a second test just to ensure that everything will be running as expected
with more volume.
Go back to the test file here.
We are going to create a million calls to the team creation representing a million calls from users.
Then we will simply check that the number of teams created is only 2.
So let's add the code for this.
Also remember to add f empty to import as we are using it in the code.
In this test we retrieved team a and team B five hundred thousand times each to reach a million users.
Then we make sure that just two objects were created.
Now save the file and move back to the terminal to run the test.
Now let's run the test command.
Go test hyphen v iPhone run equal to volume enter.
Perfect.
We can even check where the pointers are pointing to and where they are located.
So you can see we have three pointers here.
Let's check with the first three as an example.
Open the flyweight test dot go file.
We got the previous output because of these lines at the end of the test which we added.
Now in this test we used the print f method to print information about pointers.
The percent p flag gives you the memory location of the object that the pointer is pointing to.
If you reference the pointer by passing the ampersand symbol it will give you the direction of the pointer
itself.
You can see these three lines in the output.
What it tells us is that the first three positions in the map point to the same location but we actually
have three different pointers which are effectively much lighter than our team object now before we
enter this video.
Let us understand the difference between Singleton and flyweight.
Well the difference is subtle but it's just there with the Singleton pattern.
We ensure that the same type is created only once.
Also the Singleton pattern is a creation or pattern with flyweight which is a structural pattern we
aren't worried about how the objects are created but about how to structure a type to contain heavy
information in a light way.
The structure we are talking about is the map integer.
Team structure in our example here we really didn't care about how we created the object.
We have simply written and uncomplicated the get.
Team factory method for it.
We gave major importance to having a light structure to hold a shareable object or objects.
In this case the map.
Wonderful.
In this section we have seen several patterns to organize code structures structural patterns are concerned
about how to create objects or how they do their business.
We'll see this in the next part which deals with behavioral patterns.
Don't feel confused about mixing several patterns.
You could end up mixing 6 or 7 quite easily if you strictly follow the objectives of each one.
Just keep in mind that over engineering is as bad as no engineering at all.
I remember prototyping a load balancer one evening and after two hours of crazy overengineered code
I had such a mess in my head that I preferred to start all over again.
I am sure you enjoyed learning the go language along with its amazing classical patterns with me in
this first part.
At the same time I'm sure you'll join me in the next part which focuses on the behavioral patterns.
They are a bit more complex and they often use structural and creation or patterns for their objectives
but I'm sure you will find them quite challenging and interesting.
See you there.
Good bye for now.