WEBVTT 00:00.420 --> 00:01.060 Hello. 00:01.140 --> 00:07.720 We are now at the last video of this section flyweight design pattern in the previous video. 00:07.740 --> 00:11.790 We looked at facade design pattern in this video. 00:11.790 --> 00:15.570 We learned to simulate things that we find on betting Web pages. 00:15.570 --> 00:19.530 Also we will see how to store each team's information just once. 00:19.530 --> 00:23.250 And we will deliver references to them to the users. 00:23.310 --> 00:26.680 Our next pattern is the flyweight design pattern. 00:26.760 --> 00:33.450 It's very commonly used in computer graphics and video game industry but not so much in enterprise applications 00:34.020 --> 00:39.720 flyweight is a pattern which allows sharing the state of a heavy object between many instances of some 00:39.720 --> 00:40.590 type. 00:40.620 --> 00:46.650 Imagine that you have to create and store too many objects of some heavy type that are fundamentally 00:46.680 --> 00:47.510 equal. 00:47.580 --> 00:50.070 You'll run out of memory pretty quickly. 00:50.070 --> 00:55.970 This problem can be easily solved with the fly weight pattern with additional help of the factory pattern. 00:56.040 --> 01:01.890 The factory is usually in charge of encapsulating object creation as we saw previously thanks to the 01:01.890 --> 01:03.090 fly weight pattern. 01:03.090 --> 01:10.050 We can share all possible states of objects in a single common object and thus minimize object creation 01:10.050 --> 01:14.730 by using pointers to already created objects to give an example. 01:14.730 --> 01:18.990 We are going to simulate something that you find on betting Web pages. 01:18.990 --> 01:24.270 Imagine the final match of the European Championship which is viewed by millions of people across the 01:24.270 --> 01:25.350 continent. 01:25.350 --> 01:31.200 Now imagine that we own a betting Web page where we provide historical information about every team 01:31.200 --> 01:32.370 in Europe. 01:32.370 --> 01:38.280 This is plenty of information which is usually stored in some distributed database and each team has 01:38.460 --> 01:42.570 literally megabytes of information about their players matches. 01:42.570 --> 01:44.820 Championships and so on. 01:44.820 --> 01:50.460 If a million users access information about a team and a new instance of the information is created 01:50.460 --> 01:57.570 for each user querying for historical data we will run out of memory in the blink of an eye with our 01:57.570 --> 01:58.960 proxy solution. 01:58.980 --> 02:05.580 We could make a cache of the end most recent searches to speed up queries but if we return a clone for 02:05.580 --> 02:08.450 every team we will still get short on memory. 02:08.520 --> 02:12.750 But faster thanks to our cash money right. 02:12.750 --> 02:18.900 Instead we will store each team's information just once and we will deliver references to them to the 02:18.900 --> 02:19.920 users. 02:19.920 --> 02:24.960 So if we face a million users trying to access information about a match we will actually just have 02:24.960 --> 02:30.270 two teams in memory with a million pointers to the same memory direction. 02:30.270 --> 02:35.820 The acceptance criteria for a flyweight pattern must always reduce the amount of memory that is used 02:35.910 --> 02:39.840 and must be focused primarily on this objective. 02:39.840 --> 02:46.650 First we will create a team struct with basic information such as the team's name players historical 02:46.650 --> 02:50.100 results and an image depicting their shield. 02:50.100 --> 02:53.460 Next we must ensure a correct team creation. 02:53.460 --> 03:00.750 Note the word creation here candidate for a creation or pattern and not having duplicates. 03:00.750 --> 03:06.630 And secondly when creating the same team twice we must have two pointers pointing to the same memory 03:06.630 --> 03:08.060 address. 03:08.070 --> 03:15.870 Now let's move to the basic struct and tests our team struct will contain other struct inside so a total 03:15.870 --> 03:18.200 of four struct will be created. 03:18.210 --> 03:24.720 I have already two files flyweight dot go and flyweight underscore test dot go. 03:24.720 --> 03:32.310 Let me open the flyweight dot go file now let me add the package name and the import statement. 03:32.310 --> 03:36.390 Now we add the team struct it has the following signature. 03:36.390 --> 03:43.410 Each team has an I.D. and name some image and a slice of bytes representing the teams shield a slice 03:43.410 --> 03:46.510 of players and a slice of historical data. 03:46.530 --> 03:49.410 This way we will have two teams I.D.. 03:49.620 --> 03:51.630 Now let's add constants. 03:51.810 --> 03:58.380 We declare two constants by using the concept and iota keywords the concept keyword simply declares 03:58.380 --> 04:05.490 that the following declarations are constants iota is on typed integer that automatically increments 04:05.490 --> 04:12.660 its value for each new constant between the parentheses the IOTA value starts to reset to 0 when we 04:12.660 --> 04:14.250 declare Team A. 04:14.250 --> 04:20.840 So t may is equal to zero on the team B variable iota is incremented by 1. 04:20.880 --> 04:28.320 So Team B is equal to 1 the IOTA assignment is an elegant way to save typing when declaring constant 04:28.320 --> 04:34.840 values that doesn't need specific value like the PI constant on the math package. 04:34.860 --> 04:43.050 Now let's add our player and historical data lets me align this properly cool as you can see we also 04:43.050 --> 04:50.430 need a match struct which is stored within historical data struct a matched struct in this context represents 04:50.430 --> 04:53.140 the historical result of a match. 04:53.260 --> 05:00.910 Let's add the match struct this is enough to represent a team and to fulfil acceptance criteria 1 you've 05:00.930 --> 05:06.150 already guessed that there is a lot of information on each team as some of the European teams have existed 05:06.150 --> 05:13.500 for more than 100 years for acceptance criteria to the word creation should give us some clue about 05:13.500 --> 05:20.370 how to approach this problem we will build a factory to create and store our teams our factory will 05:20.370 --> 05:28.140 consist of a map of years including pointers to teams as values and a get team function using a map 05:28.170 --> 05:34.350 will boost the team search if we know their names in advance we will also dispose of a method to return 05:34.350 --> 05:38.700 the number of created objects which will be called to get number of objects. 05:38.700 --> 05:41.970 Method so let's add this method. 05:42.140 --> 05:45.090 This is enough to write our first unit test. 05:45.290 --> 05:48.630 Let's save this file and go back to flyweight test. 05:48.690 --> 05:56.940 Don't go and we add test function over here in our test we verify all the acceptance criteria. 05:56.940 --> 06:01.800 First we create a factory and then ask for a pointer of Team A. 06:01.920 --> 06:05.670 This pointer cannot be nil or the test will fail. 06:05.940 --> 06:08.920 Then we call for a second pointed to the same team. 06:08.940 --> 06:14.080 This pointer can't be nil either and it should point to the same memory address as the previous one. 06:14.130 --> 06:18.090 So we know that it has not allocated a new memory. 06:18.090 --> 06:23.010 Finally we should check whether the number of created teams is only 1 because we have asked for the 06:23.010 --> 06:24.630 same team twice. 06:24.630 --> 06:32.370 We have two pointers but just one instance of the team go to the terminal and now run the tests. 06:32.370 --> 06:33.810 Well it failed. 06:33.810 --> 06:37.400 Both pointers were nil and it has not created any object. 06:37.410 --> 06:45.410 Interestingly the function that compares the two pointers doesn't fail all in all nil equals nil Now 06:45.410 --> 06:52.310 let's move to implementation our get team method will need to scan the map field calls created teams 06:52.310 --> 06:56.180 to make sure the query team is already created and return it. 06:56.180 --> 07:03.450 If so if the team wasn't created it will have to create it and store it in the map before returning. 07:03.460 --> 07:09.050 Let's go to our flyweight dot go file and we need to modify this code. 07:09.050 --> 07:10.510 This code is very simple. 07:10.610 --> 07:15.290 If the parameter name exists in the created teams map return the pointer. 07:15.500 --> 07:18.800 Otherwise call a factory for Team creation. 07:18.800 --> 07:24.230 This is interesting enough to stop for a second and analyze when you use the fly weight pattern. 07:24.230 --> 07:30.140 It is very common to have a fly weight factory which uses other types of creation or patterns to retrieve 07:30.140 --> 07:32.150 the objects it needs. 07:32.450 --> 07:36.720 So the get team factory method will give us the team we are looking for. 07:36.770 --> 07:39.680 We will store it in the map and return it. 07:39.770 --> 07:44.960 The team factory will be able to create two teams team a and Team B. 07:45.080 --> 07:50.480 Let's add the get team factory method with the switch statement. 07:50.530 --> 07:56.350 We are simplifying the object's content so that we can focus on the fly weight patterns implementation. 07:56.350 --> 08:01.900 Okay so we just have to define the function to retrieve the number of objects created which is done 08:02.020 --> 08:03.670 as I show you. 08:03.670 --> 08:07.030 We need to modify the return statement. 08:07.040 --> 08:08.630 This was pretty easy. 08:08.630 --> 08:14.060 The lend function returns the number of elements in an array or slice the number of characters in a 08:14.060 --> 08:15.530 string and so on. 08:15.530 --> 08:22.010 It seems that everything is done and we can launch our tests again save the file and move to the terminal 08:22.880 --> 08:24.200 execute the command. 08:24.200 --> 08:31.790 Go test hyphen v hyphen run equal to get team enter panic. 08:31.880 --> 08:38.180 Have we forgotten something by reading the stack trace on the panic method we can see some addresses 08:38.240 --> 08:44.730 some files and it seems that the get team method is trying to assign an entry to a nil map online seventy 08:44.730 --> 08:50.970 one of the fly Wait don't go file let's look at line 71 closely. 08:51.320 --> 08:53.660 And here is the line which we were searching for. 08:53.660 --> 08:56.570 You can find it more easily with your editor. 08:56.570 --> 09:01.520 Remember if you are writing code while following this tutorial that the error will probably be in a 09:01.520 --> 09:04.310 different line so look closely at your own stock. 09:04.310 --> 09:12.050 Trace okay this line is on the Get team method and when the method passes through here it means that 09:12.050 --> 09:16.130 it had not found the team on the map that has created it. 09:16.280 --> 09:23.210 The variable team and is trying to assign it to the map but the map is nil because we haven't initialized 09:23.210 --> 09:23.360 it. 09:23.360 --> 09:28.160 When creating the factory I'm sure you've seen the problem here already. 09:28.160 --> 09:33.590 If we don't have access to the package we can initialize the variable Well we can make the variable 09:33.590 --> 09:35.150 public and that's all. 09:35.300 --> 09:41.570 But this would involve every implementer necessarily knowing that they have to initialize the map and 09:41.570 --> 09:45.050 its signature is neither convenient or elegant. 09:45.050 --> 09:50.340 Instead we are going to create a simple factory builder to do it for us. 09:50.360 --> 09:55.370 This is a very common approach in go so let's build a new team factory. 09:55.370 --> 09:58.490 Let's save this file and go to flyweight test. 09:58.510 --> 10:01.260 Don't go now in the test. 10:01.310 --> 10:08.540 We replace the factory creation with a call to this function save the file and move to the terminal. 10:08.540 --> 10:10.740 Now let's run the test again. 10:10.850 --> 10:11.930 Perfect. 10:11.990 --> 10:18.170 Let's improve the test by adding a second test just to ensure that everything will be running as expected 10:18.170 --> 10:19.780 with more volume. 10:19.850 --> 10:22.730 Go back to the test file here. 10:22.780 --> 10:29.390 We are going to create a million calls to the team creation representing a million calls from users. 10:29.470 --> 10:34.860 Then we will simply check that the number of teams created is only 2. 10:34.930 --> 10:37.130 So let's add the code for this. 10:37.150 --> 10:41.850 Also remember to add f empty to import as we are using it in the code. 10:42.910 --> 10:50.170 In this test we retrieved team a and team B five hundred thousand times each to reach a million users. 10:50.200 --> 10:53.750 Then we make sure that just two objects were created. 10:53.830 --> 10:57.630 Now save the file and move back to the terminal to run the test. 10:58.500 --> 11:00.480 Now let's run the test command. 11:00.480 --> 11:06.050 Go test hyphen v iPhone run equal to volume enter. 11:06.360 --> 11:07.380 Perfect. 11:07.380 --> 11:11.700 We can even check where the pointers are pointing to and where they are located. 11:11.910 --> 11:14.490 So you can see we have three pointers here. 11:15.030 --> 11:18.330 Let's check with the first three as an example. 11:18.330 --> 11:21.190 Open the flyweight test dot go file. 11:21.390 --> 11:26.430 We got the previous output because of these lines at the end of the test which we added. 11:26.610 --> 11:31.950 Now in this test we used the print f method to print information about pointers. 11:31.950 --> 11:36.990 The percent p flag gives you the memory location of the object that the pointer is pointing to. 11:37.560 --> 11:42.780 If you reference the pointer by passing the ampersand symbol it will give you the direction of the pointer 11:42.840 --> 11:44.540 itself. 11:44.550 --> 11:47.820 You can see these three lines in the output. 11:47.820 --> 11:53.940 What it tells us is that the first three positions in the map point to the same location but we actually 11:53.940 --> 12:01.010 have three different pointers which are effectively much lighter than our team object now before we 12:01.010 --> 12:02.160 enter this video. 12:02.160 --> 12:06.920 Let us understand the difference between Singleton and flyweight. 12:06.920 --> 12:11.620 Well the difference is subtle but it's just there with the Singleton pattern. 12:11.630 --> 12:14.920 We ensure that the same type is created only once. 12:14.960 --> 12:21.230 Also the Singleton pattern is a creation or pattern with flyweight which is a structural pattern we 12:21.230 --> 12:27.050 aren't worried about how the objects are created but about how to structure a type to contain heavy 12:27.050 --> 12:29.490 information in a light way. 12:29.660 --> 12:32.390 The structure we are talking about is the map integer. 12:32.390 --> 12:38.040 Team structure in our example here we really didn't care about how we created the object. 12:38.090 --> 12:41.210 We have simply written and uncomplicated the get. 12:41.210 --> 12:43.600 Team factory method for it. 12:43.820 --> 12:49.330 We gave major importance to having a light structure to hold a shareable object or objects. 12:49.340 --> 12:51.050 In this case the map. 12:51.050 --> 12:51.920 Wonderful. 12:51.920 --> 12:58.190 In this section we have seen several patterns to organize code structures structural patterns are concerned 12:58.190 --> 13:01.700 about how to create objects or how they do their business. 13:01.730 --> 13:06.110 We'll see this in the next part which deals with behavioral patterns. 13:06.260 --> 13:08.930 Don't feel confused about mixing several patterns. 13:08.990 --> 13:14.980 You could end up mixing 6 or 7 quite easily if you strictly follow the objectives of each one. 13:14.990 --> 13:19.830 Just keep in mind that over engineering is as bad as no engineering at all. 13:19.850 --> 13:25.640 I remember prototyping a load balancer one evening and after two hours of crazy overengineered code 13:25.880 --> 13:29.420 I had such a mess in my head that I preferred to start all over again. 13:29.480 --> 13:34.670 I am sure you enjoyed learning the go language along with its amazing classical patterns with me in 13:34.670 --> 13:36.100 this first part. 13:36.170 --> 13:41.630 At the same time I'm sure you'll join me in the next part which focuses on the behavioral patterns. 13:41.660 --> 13:47.030 They are a bit more complex and they often use structural and creation or patterns for their objectives 13:47.330 --> 13:51.220 but I'm sure you will find them quite challenging and interesting. 13:51.290 --> 13:52.250 See you there. 13:52.250 --> 13:52.990 Good bye for now.