WEBVTT 00:00.480 --> 00:01.180 Hello. 00:01.290 --> 00:05.580 This is the last video of this section bridge design pattern. 00:05.580 --> 00:10.410 Previously we explored about the adapter design pattern in this video. 00:10.530 --> 00:15.120 We will go to a console printer abstraction and have two implementations. 00:15.180 --> 00:20.660 We will write to an I O dot writer interface to provide more flexibility to the solution. 00:20.670 --> 00:28.050 We will also have to abstracted object users of the implementations the bridge design pattern is a design 00:28.050 --> 00:34.800 with a slightly cryptic definition from the original Gang of Four book it d couples and abstraction 00:34.980 --> 00:39.300 from its implementation so that the two can vary independently. 00:39.300 --> 00:45.840 This cryptic explanation just means that you could even decouple the most basic form of functionality 00:46.170 --> 00:49.050 decouple an object from what it does. 00:49.320 --> 00:53.940 The bridge pattern tries to decouple things as usual with design patterns. 00:54.090 --> 01:00.630 It decoupling abstraction that is an object from its implementation or the thing that the object does. 01:00.630 --> 01:04.820 This way we can change what an object does as much as we want. 01:04.830 --> 01:11.010 It also allows us to change the abstracted object while reusing the same implementation. 01:11.010 --> 01:16.860 The objective of the bridge pattern is to bring flexibility to a struct that change often knowing the 01:16.860 --> 01:19.200 inputs and outputs of a method. 01:19.200 --> 01:25.080 It allows us to change code without knowing too much about it and leaving the freedom for both sides 01:25.080 --> 01:27.300 to be modified more easily. 01:27.360 --> 01:32.080 For our example we will go to a console printer abstraction to keep it simple. 01:32.160 --> 01:34.210 We will have two implementations. 01:34.260 --> 01:36.560 The first will write to the console. 01:36.660 --> 01:42.090 Having learned about the I O dot writer interface in the previous section we will make the second right 01:42.120 --> 01:47.370 to an I O dot writer interface to provide more flexibility to the solution. 01:47.370 --> 01:53.670 We will also have to abstract it object users of the implementations and normal object which will use 01:53.760 --> 01:59.430 each implementation in a straightforward manner and a packed implementation which will append to the 01:59.430 --> 02:05.110 sentence message from packed to the printing message at the end of this section. 02:05.160 --> 02:10.530 We will have to abstraction objects which have two different implementations of their functionality. 02:10.530 --> 02:17.670 So actually we will have 22 possible combinations of object functionality as we mentioned previously. 02:17.760 --> 02:23.880 We will have two objects that is packed and normal printer and two implementations which are printer 02:23.970 --> 02:26.940 implementation one and printer implementation. 02:26.940 --> 02:31.920 Two that we will join by using the bridge design pattern more or less. 02:31.920 --> 02:35.580 We will have these requirements and acceptance criteria. 02:35.580 --> 02:42.300 A printer API that accepts a message to print an implementation of the API that simply prints the message 02:42.300 --> 02:43.500 to the console. 02:43.680 --> 02:51.210 An implementation of the API that prints to an I O dot writer interface a printer abstraction with a 02:51.210 --> 02:57.570 print method to implement in printing types a normal printer object which will implement the printer 02:57.600 --> 02:59.830 and printer API interface. 02:59.970 --> 03:05.730 The normal printer will forward the message directly to the implementation a packed printer which will 03:05.730 --> 03:10.140 implement the printer abstraction and the printer API interface. 03:10.140 --> 03:16.870 And lastly the packed printer will append the message message from packed to all prints. 03:16.910 --> 03:20.200 We now move on to unit testing the bridge pattern. 03:20.240 --> 03:22.860 Open the bridge dot go file. 03:22.970 --> 03:30.170 Let's start with acceptance criteria 1 the printer API interface implementers of this interface must 03:30.170 --> 03:35.280 provide a print message method that will print the message past as an argument. 03:35.510 --> 03:41.640 Next we passed two acceptance criteria 2 with an implementation of the previous API. 03:41.870 --> 03:48.320 Our printer implementation one is a type that implements the printer API interface by providing an implementation 03:48.320 --> 03:50.690 of the print message method. 03:50.690 --> 03:54.740 The print message method is not implemented yet and returns an error. 03:54.740 --> 04:01.640 This is enough to write our first unit test to cover printer implementation one so I have written our 04:01.640 --> 04:03.860 first test in the bridge test. 04:03.890 --> 04:12.860 Dot go file in our test to cover print API 1 we create an instance of printer implementation one type. 04:13.040 --> 04:20.300 Then we use its print message method to print the message hello to the console as we have no implementations 04:20.300 --> 04:22.580 yet it must return the error string. 04:22.580 --> 04:29.450 Not implemented yet as shown in our bridge dot go file let us go back to the terminal and execute the 04:29.450 --> 04:31.100 test command. 04:31.190 --> 04:34.640 Whoops I forgot to define testing bridge test Dot. 04:34.640 --> 04:37.100 Go file let's do it. 04:37.100 --> 04:42.860 Add import and in parentheses and double inverted comma testing. 04:42.860 --> 04:44.070 Save the file. 04:44.090 --> 04:47.900 Let's go to the terminal and execute the same command again. 04:47.930 --> 04:51.340 Call is the output okay. 04:51.360 --> 04:58.080 Now we have to write the second API test that will work with an I O dot writer interface open the bridge 04:58.080 --> 05:02.430 dot go file and let's add the second printer implementation. 05:02.490 --> 05:12.920 Also we need to add I O in the import section now save the file as you can see our printer implementation 05:13.060 --> 05:17.170 to struct stores and I O dot writer implementer. 05:17.240 --> 05:22.490 Also our print message method follows the printer API interface. 05:22.490 --> 05:27.800 Now that we're familiar with the IO dot writer interface we're going to make a test object that implements 05:27.830 --> 05:32.270 this interface and does whatever is written to it in a local field. 05:32.270 --> 05:35.970 This will help us check the contents that are being sent through the writer. 05:36.170 --> 05:44.610 So let us go to our test file that is bridge underscore test dot go and a few lines of code here in 05:44.610 --> 05:49.870 our test object we checked that the content isn't empty before writing it to the local field. 05:49.950 --> 05:56.630 If it's empty we return the error and if not we write the contents of P in the message field. 05:56.670 --> 06:03.720 Let's use this small struct in the next tests for the second API which I add now fine. 06:03.820 --> 06:05.580 Let's stop for a second here. 06:05.590 --> 06:12.100 We created an instance of printer implementation too called API 2 in the first line of the preceding 06:12.100 --> 06:13.060 code. 06:13.060 --> 06:19.900 We haven't passed any instance of IO dot writer on purpose so we also checked that we actually receive 06:19.900 --> 06:20.990 an error first. 06:21.070 --> 06:27.040 Then we try to use its print message method but we must get an error because it doesn't have any I O 06:27.040 --> 06:30.310 dot writer instance stored in the right field. 06:30.430 --> 06:37.480 The error must be you need to pass an I O dot writer to printer implementation too and we implicitly 06:37.480 --> 06:39.740 check the contents of the error. 06:39.770 --> 06:41.250 Let's continue with the test. 06:41.350 --> 06:46.780 Next add these lines of code for the second part of this unit test. 06:46.780 --> 06:53.320 We use an instance of the test writer object as an I O dot writer interface test writer. 06:53.590 --> 06:59.160 We pass the message Hello to API 2 and checked whether we received any error. 06:59.260 --> 07:03.340 Then we check the contents of the test writer dot message field. 07:03.340 --> 07:09.490 Remember that we have written an IO dot writer interface that stored any bytes passed to its right method 07:09.640 --> 07:11.080 in the message field. 07:11.080 --> 07:16.090 If everything is correct the message should contain the word hello. 07:16.090 --> 07:21.030 These were our tests for printer implementation too as we do not have any implementations yet. 07:21.100 --> 07:24.110 We should get a few errors when running this test. 07:24.160 --> 07:29.170 Also you need to import strings and errors packages. 07:29.170 --> 07:32.710 Let's save this file and go back to the terminal. 07:32.860 --> 07:36.400 Now run the test command and here's the output. 07:36.670 --> 07:38.910 At least one test passes. 07:39.010 --> 07:41.660 The one that checks that an error message is being returned. 07:41.740 --> 07:48.280 When using the print message without Io dot right being stored everything else fails as expected at 07:48.280 --> 07:49.930 this stage. 07:49.960 --> 07:55.320 Now we need a printer abstraction for objects that can use printer API implementers. 07:55.420 --> 08:00.400 We will define this as the printer abstraction interface with a print method. 08:00.430 --> 08:08.520 This covers the acceptance criteria for let's add the code for it in the bridge dot go file for acceptance 08:08.520 --> 08:09.060 criteria. 08:09.060 --> 08:16.980 5 We need a normal printer a printer abstraction will need a field to store a printer API so our normal 08:16.980 --> 08:19.190 printer looks like this. 08:19.260 --> 08:22.800 This is enough to write a unit test for the print method. 08:22.800 --> 08:25.140 Let's save the file. 08:25.370 --> 08:28.620 Now go to the unit test which we have added in the bridge test. 08:28.910 --> 08:32.310 Go file and add these lines of code. 08:32.330 --> 08:37.370 Now the first part of the test checks that the print method isn't implemented yet. 08:37.460 --> 08:43.460 When using printer implementation one printer API interface the message will use along. 08:43.460 --> 08:50.270 This test is hello I O dot writer with a printer implementation one we don't have an easy way to check 08:50.270 --> 08:55.160 the contents of the message as we print directly to the console checking. 08:55.190 --> 09:03.770 In this case is visual so we can check acceptance criteria 6 so let's again add the code this time for 09:03.770 --> 09:05.950 acceptance criteria six. 09:06.050 --> 09:14.510 Okay the next part of normal printer tests uses printer implementation to the one that needs an I O 09:14.580 --> 09:16.850 dot writer interface implementer. 09:16.950 --> 09:21.770 We reuse our test writer struct here to check the contents of the message. 09:21.810 --> 09:28.260 So in short we want a normal printer struct that accepts a message of type String and the printer of 09:28.260 --> 09:36.270 type printer API at this point if I use the print method I shouldn't get any error and the message failed 09:36.270 --> 09:42.570 on test writer must contain the message we passed to normal printer on its initialization. 09:42.570 --> 09:46.140 Now save the file and navigate to the terminal. 09:46.140 --> 09:50.030 Let's run the tests. 09:50.090 --> 09:57.020 There is a trick to quickly check the validity of a unit test the number of times we called T dot error 09:57.230 --> 09:58.680 or T dot error. 09:58.700 --> 10:05.720 F must match the number of messages of error on the console and the lines where they were produced in 10:05.720 --> 10:07.000 the previous test results. 10:07.010 --> 10:15.890 There are three errors at lines 59 70 and 73 which exactly match the checks we wrote our packed printer 10:15.890 --> 10:16.580 struct. 10:16.610 --> 10:20.130 We'll have a very similar definition to normal printer at this point. 10:20.130 --> 10:21.700 Let's go back to our bridge Dot. 10:21.740 --> 10:24.830 Go file and continue adding code. 10:24.920 --> 10:28.340 So this is our packed printer. 10:28.400 --> 10:34.310 This covers acceptance criteria 7 and we can almost copy and paste the contents of the previous test 10:34.640 --> 10:36.300 with a few changes. 10:36.340 --> 10:40.640 Let's go to test dot go and add these lines of code. 10:40.850 --> 10:45.060 Save the file what have we changed here. 10:45.080 --> 10:50.150 Now we have passed message which represents the message we are passing to packed printer. 10:50.150 --> 10:56.020 We also have an expected message that contains the prefixed message from pact. 10:56.090 --> 10:57.900 If you remember acceptance criteria. 10:57.920 --> 11:06.110 8 this abstraction must prefix the text message from packed to any message that is passed to it and 11:06.110 --> 11:12.170 at the same time it must be able to use any implementation of a printer API interface. 11:12.170 --> 11:18.900 The second changes that we actually create packed printer struts instead of the normal printer struts. 11:19.040 --> 11:20.960 Everything else is the same. 11:20.960 --> 11:23.730 Let's save the file and go back to the terminal. 11:23.750 --> 11:25.590 It looks quite messy. 11:25.640 --> 11:27.950 Let me clear the screen. 11:27.950 --> 11:31.850 Now let's run the test again and here's the output. 11:31.850 --> 11:33.860 Three checks three errors. 11:34.010 --> 11:39.060 All tests have been covered and we can finally move on to the implementation. 11:39.080 --> 11:40.310 Amazing. 11:40.310 --> 11:46.100 We start implementing in the same order that we created our tests first with the printer implementation 11:46.100 --> 11:47.280 one definition. 11:47.330 --> 11:50.290 So let's to our bridge dot go. 11:50.570 --> 11:54.710 Let's change the definition and make some changes to our code. 11:54.710 --> 11:58.830 Replace the print implementation one function with these lines. 11:58.830 --> 12:06.860 Okay our first API takes the message M S G and prints it to the console in the case of an empty string. 12:06.860 --> 12:08.290 Nothing will be printed. 12:08.360 --> 12:10.940 This is enough to pass the first test. 12:10.940 --> 12:14.750 Let's save the file and move to the terminal and run the test. 12:14.750 --> 12:17.160 So we have passed the test. 12:17.210 --> 12:20.710 You can see the hello message in the second line of the output of the test. 12:20.810 --> 12:27.130 Just after the run message the printer implementation to struct isn't very complex either. 12:27.140 --> 12:33.200 The difference is that instead of printing to the console we are going to write on an I O dot writer 12:33.200 --> 12:36.370 interface which must be stored in the struct. 12:36.500 --> 12:43.790 So let's make the changes to the second implementation to and save the file as defined in our tests. 12:43.820 --> 12:48.880 We check the contents of the right a field first and return to the expected error message. 12:48.920 --> 12:53.370 You need to pass an IO dot writer to printer implementation to. 12:53.420 --> 12:55.200 If nothing is stored. 12:55.250 --> 12:57.980 This is the message we'll check later in the test. 12:57.980 --> 13:06.140 Then the F empty dot F print f method takes an I O dot writer interface as the first field and a message 13:06.140 --> 13:07.700 formatted as the rest. 13:07.700 --> 13:13.790 So we simply forward the contents of the message argument to the I O dot right to provided save the 13:13.790 --> 13:18.540 file and go back to the terminal to run the test for the print API too. 13:18.680 --> 13:21.360 So we have passed this test also. 13:21.770 --> 13:24.810 Now we'll continue with the normal printer. 13:25.100 --> 13:31.040 This printer must simply forward the message to the printer API interface stored without any modification 13:31.640 --> 13:32.410 in our test. 13:32.420 --> 13:38.300 We are using two implementations of printer API one that prints to the console and one that writes to 13:38.300 --> 13:40.510 an IO dot writer interface. 13:40.560 --> 13:43.340 Let's replace the normal print function. 13:43.340 --> 13:46.090 We returned nil as no error has occurred. 13:46.100 --> 13:48.930 This should be enough to pass the unit tests. 13:49.090 --> 13:57.070 Let us run the test in this output you can see the halo I O dot right a message that the printer implementation 13:57.070 --> 14:03.610 one struct writes to SD d out we can consider this check as having passed. 14:03.810 --> 14:09.880 Finally the packed printer method is similar to normal printer but it just prefixes every message with 14:09.880 --> 14:12.540 the text message from packed. 14:12.540 --> 14:17.550 Now let's modify the pact printer function like in the normal printer method. 14:17.550 --> 14:22.620 We accepted a message string and a printer API implementation in the printer field. 14:22.710 --> 14:30.540 Then we used the F empty dot Sprint f method to compose a new string with the text message from packed 14:30.810 --> 14:32.360 and the provided message. 14:32.490 --> 14:38.200 We took the composed text and passed it to the print message method of print API stored in the printer 14:38.210 --> 14:44.840 field of the packed printer struct let us save the file and move to the terminal to execute the test 14:44.840 --> 14:46.190 command. 14:46.190 --> 14:48.370 So we have passed this test too. 14:48.380 --> 14:49.610 Wonderful. 14:49.610 --> 14:55.940 Again you can see the results of using printer implementation one for writing to SD D out with the text 14:56.150 --> 15:03.680 message from packed hello I O dots writer this last test should cover all of our code in the bridge 15:03.680 --> 15:09.530 pattern as you have seen previously you can check the coverage by using the hyphen cover flag so let's 15:09.620 --> 15:18.910 execute the command go test hyphen cover enter Wow a hundred percent coverage this looks good however 15:18.940 --> 15:23.620 this doesn't mean that the code is perfect we haven't checked that the contents of the messages weren't 15:23.710 --> 15:24.520 empty. 15:24.520 --> 15:30.250 Maybe something that should be avoided but it isn't a part of our requirements which is also an important 15:30.250 --> 15:31.020 point. 15:31.210 --> 15:37.060 Just because some feature isn't in the requirements or the acceptance criteria doesn't mean that it 15:37.060 --> 15:40.280 shouldn't be covered with the bridge pattern. 15:40.330 --> 15:46.380 We have learned how to uncouple an object and its implementation for the print message method. 15:46.390 --> 15:51.100 This way we can reuse its abstractions as well as its implementations. 15:51.100 --> 15:56.140 We can swap the printer abstractions as well as the printer API is as much as we want without affecting 15:56.140 --> 15:57.580 the user code. 15:57.940 --> 16:03.910 In this section we have seen the power of composition and many of the ways that go takes advantage of 16:03.910 --> 16:06.090 it by its own nature. 16:06.100 --> 16:11.680 We've seen that adapter pattern can help us make two incompatible interfaces work together by using 16:11.680 --> 16:15.040 an adapter object in between at the same time. 16:15.070 --> 16:20.740 We've seen some real life examples in Ghost source code where the creators of the language used this 16:20.740 --> 16:25.660 design pattern to improve the possibilities of some particular piece of the standard library. 16:26.380 --> 16:32.170 Finally we have seen the bridge pattern and its possibilities allowing us to create swapping structures 16:32.350 --> 16:38.510 with complete reuse ability between objects and their implementations in the next section. 16:38.590 --> 16:41.530 We will explore more about structural patterns.