Hello.
This is the last video of this section bridge design pattern.
Previously we explored about the adapter design pattern in this video.
We will go to a console printer abstraction and have two implementations.
We will write to an I O dot writer interface to provide more flexibility to the solution.
We will also have to abstracted object users of the implementations the bridge design pattern is a design
with a slightly cryptic definition from the original Gang of Four book it d couples and abstraction
from its implementation so that the two can vary independently.
This cryptic explanation just means that you could even decouple the most basic form of functionality
decouple an object from what it does.
The bridge pattern tries to decouple things as usual with design patterns.
It decoupling abstraction that is an object from its implementation or the thing that the object does.
This way we can change what an object does as much as we want.
It also allows us to change the abstracted object while reusing the same implementation.
The objective of the bridge pattern is to bring flexibility to a struct that change often knowing the
inputs and outputs of a method.
It allows us to change code without knowing too much about it and leaving the freedom for both sides
to be modified more easily.
For our example we will go to a console printer abstraction to keep it simple.
We will have two implementations.
The first will write to the console.
Having learned about the I O dot writer interface in the previous section we will make the second right
to an I O dot writer interface to provide more flexibility to the solution.
We will also have to abstract it object users of the implementations and normal object which will use
each implementation in a straightforward manner and a packed implementation which will append to the
sentence message from packed to the printing message at the end of this section.
We will have to abstraction objects which have two different implementations of their functionality.
So actually we will have 22 possible combinations of object functionality as we mentioned previously.
We will have two objects that is packed and normal printer and two implementations which are printer
implementation one and printer implementation.
Two that we will join by using the bridge design pattern more or less.
We will have these requirements and acceptance criteria.
A printer API that accepts a message to print an implementation of the API that simply prints the message
to the console.
An implementation of the API that prints to an I O dot writer interface a printer abstraction with a
print method to implement in printing types a normal printer object which will implement the printer
and printer API interface.
The normal printer will forward the message directly to the implementation a packed printer which will
implement the printer abstraction and the printer API interface.
And lastly the packed printer will append the message message from packed to all prints.
We now move on to unit testing the bridge pattern.
Open the bridge dot go file.
Let's start with acceptance criteria 1 the printer API interface implementers of this interface must
provide a print message method that will print the message past as an argument.
Next we passed two acceptance criteria 2 with an implementation of the previous API.
Our printer implementation one is a type that implements the printer API interface by providing an implementation
of the print message method.
The print message method is not implemented yet and returns an error.
This is enough to write our first unit test to cover printer implementation one so I have written our
first test in the bridge test.
Dot go file in our test to cover print API 1 we create an instance of printer implementation one type.
Then we use its print message method to print the message hello to the console as we have no implementations
yet it must return the error string.
Not implemented yet as shown in our bridge dot go file let us go back to the terminal and execute the
test command.
Whoops I forgot to define testing bridge test Dot.
Go file let's do it.
Add import and in parentheses and double inverted comma testing.
Save the file.
Let's go to the terminal and execute the same command again.
Call is the output okay.
Now we have to write the second API test that will work with an I O dot writer interface open the bridge
dot go file and let's add the second printer implementation.
Also we need to add I O in the import section now save the file as you can see our printer implementation
to struct stores and I O dot writer implementer.
Also our print message method follows the printer API interface.
Now that we're familiar with the IO dot writer interface we're going to make a test object that implements
this interface and does whatever is written to it in a local field.
This will help us check the contents that are being sent through the writer.
So let us go to our test file that is bridge underscore test dot go and a few lines of code here in
our test object we checked that the content isn't empty before writing it to the local field.
If it's empty we return the error and if not we write the contents of P in the message field.
Let's use this small struct in the next tests for the second API which I add now fine.
Let's stop for a second here.
We created an instance of printer implementation too called API 2 in the first line of the preceding
code.
We haven't passed any instance of IO dot writer on purpose so we also checked that we actually receive
an error first.
Then we try to use its print message method but we must get an error because it doesn't have any I O
dot writer instance stored in the right field.
The error must be you need to pass an I O dot writer to printer implementation too and we implicitly
check the contents of the error.
Let's continue with the test.
Next add these lines of code for the second part of this unit test.
We use an instance of the test writer object as an I O dot writer interface test writer.
We pass the message Hello to API 2 and checked whether we received any error.
Then we check the contents of the test writer dot message field.
Remember that we have written an IO dot writer interface that stored any bytes passed to its right method
in the message field.
If everything is correct the message should contain the word hello.
These were our tests for printer implementation too as we do not have any implementations yet.
We should get a few errors when running this test.
Also you need to import strings and errors packages.
Let's save this file and go back to the terminal.
Now run the test command and here's the output.
At least one test passes.
The one that checks that an error message is being returned.
When using the print message without Io dot right being stored everything else fails as expected at
this stage.
Now we need a printer abstraction for objects that can use printer API implementers.
We will define this as the printer abstraction interface with a print method.
This covers the acceptance criteria for let's add the code for it in the bridge dot go file for acceptance
criteria.
5 We need a normal printer a printer abstraction will need a field to store a printer API so our normal
printer looks like this.
This is enough to write a unit test for the print method.
Let's save the file.
Now go to the unit test which we have added in the bridge test.
Go file and add these lines of code.
Now the first part of the test checks that the print method isn't implemented yet.
When using printer implementation one printer API interface the message will use along.
This test is hello I O dot writer with a printer implementation one we don't have an easy way to check
the contents of the message as we print directly to the console checking.
In this case is visual so we can check acceptance criteria 6 so let's again add the code this time for
acceptance criteria six.
Okay the next part of normal printer tests uses printer implementation to the one that needs an I O
dot writer interface implementer.
We reuse our test writer struct here to check the contents of the message.
So in short we want a normal printer struct that accepts a message of type String and the printer of
type printer API at this point if I use the print method I shouldn't get any error and the message failed
on test writer must contain the message we passed to normal printer on its initialization.
Now save the file and navigate to the terminal.
Let's run the tests.
There is a trick to quickly check the validity of a unit test the number of times we called T dot error
or T dot error.
F must match the number of messages of error on the console and the lines where they were produced in
the previous test results.
There are three errors at lines 59 70 and 73 which exactly match the checks we wrote our packed printer
struct.
We'll have a very similar definition to normal printer at this point.
Let's go back to our bridge Dot.
Go file and continue adding code.
So this is our packed printer.
This covers acceptance criteria 7 and we can almost copy and paste the contents of the previous test
with a few changes.
Let's go to test dot go and add these lines of code.
Save the file what have we changed here.
Now we have passed message which represents the message we are passing to packed printer.
We also have an expected message that contains the prefixed message from pact.
If you remember acceptance criteria.
8 this abstraction must prefix the text message from packed to any message that is passed to it and
at the same time it must be able to use any implementation of a printer API interface.
The second changes that we actually create packed printer struts instead of the normal printer struts.
Everything else is the same.
Let's save the file and go back to the terminal.
It looks quite messy.
Let me clear the screen.
Now let's run the test again and here's the output.
Three checks three errors.
All tests have been covered and we can finally move on to the implementation.
Amazing.
We start implementing in the same order that we created our tests first with the printer implementation
one definition.
So let's to our bridge dot go.
Let's change the definition and make some changes to our code.
Replace the print implementation one function with these lines.
Okay our first API takes the message M S G and prints it to the console in the case of an empty string.
Nothing will be printed.
This is enough to pass the first test.
Let's save the file and move to the terminal and run the test.
So we have passed the test.
You can see the hello message in the second line of the output of the test.
Just after the run message the printer implementation to struct isn't very complex either.
The difference is that instead of printing to the console we are going to write on an I O dot writer
interface which must be stored in the struct.
So let's make the changes to the second implementation to and save the file as defined in our tests.
We check the contents of the right a field first and return to the expected error message.
You need to pass an IO dot writer to printer implementation to.
If nothing is stored.
This is the message we'll check later in the test.
Then the F empty dot F print f method takes an I O dot writer interface as the first field and a message
formatted as the rest.
So we simply forward the contents of the message argument to the I O dot right to provided save the
file and go back to the terminal to run the test for the print API too.
So we have passed this test also.
Now we'll continue with the normal printer.
This printer must simply forward the message to the printer API interface stored without any modification
in our test.
We are using two implementations of printer API one that prints to the console and one that writes to
an IO dot writer interface.
Let's replace the normal print function.
We returned nil as no error has occurred.
This should be enough to pass the unit tests.
Let us run the test in this output you can see the halo I O dot right a message that the printer implementation
one struct writes to SD d out we can consider this check as having passed.
Finally the packed printer method is similar to normal printer but it just prefixes every message with
the text message from packed.
Now let's modify the pact printer function like in the normal printer method.
We accepted a message string and a printer API implementation in the printer field.
Then we used the F empty dot Sprint f method to compose a new string with the text message from packed
and the provided message.
We took the composed text and passed it to the print message method of print API stored in the printer
field of the packed printer struct let us save the file and move to the terminal to execute the test
command.
So we have passed this test too.
Wonderful.
Again you can see the results of using printer implementation one for writing to SD D out with the text
message from packed hello I O dots writer this last test should cover all of our code in the bridge
pattern as you have seen previously you can check the coverage by using the hyphen cover flag so let's
execute the command go test hyphen cover enter Wow a hundred percent coverage this looks good however
this doesn't mean that the code is perfect we haven't checked that the contents of the messages weren't
empty.
Maybe something that should be avoided but it isn't a part of our requirements which is also an important
point.
Just because some feature isn't in the requirements or the acceptance criteria doesn't mean that it
shouldn't be covered with the bridge pattern.
We have learned how to uncouple an object and its implementation for the print message method.
This way we can reuse its abstractions as well as its implementations.
We can swap the printer abstractions as well as the printer API is as much as we want without affecting
the user code.
In this section we have seen the power of composition and many of the ways that go takes advantage of
it by its own nature.
We've seen that adapter pattern can help us make two incompatible interfaces work together by using
an adapter object in between at the same time.
We've seen some real life examples in Ghost source code where the creators of the language used this
design pattern to improve the possibilities of some particular piece of the standard library.
Finally we have seen the bridge pattern and its possibilities allowing us to create swapping structures
with complete reuse ability between objects and their implementations in the next section.
We will explore more about structural patterns.