So now we're going to actually look at a more large implementation of the bridge design pattern.
We're going to consider this idea of rendering different objects.
So as I've mentioned when I was introducing the bridge design pattern one of the goals of the bridge
is to avoid the state space explosion so let me give you an example let's suppose that we have different
kinds of shapes.
So we have several different kinds of shapes like for example you might have a circle or a square and
you might also have different ways of rendering those shapes so you have this idea of a renderer and
that can be a roster ender that renders pixels or a vector renderer that renders using lines.
So one of the things that the bridge pattern helps us avoid is this idea of creating a kind of cartesian
product in terms of the renderers So for example if you want to render circles and squares in both raster
and vector form you could end up with a two by two situation so you can end up with a let's say a roster
circle renderer you'd have a roster square Aranda you would have a vector circle renderer and so on
while you get the idea of it you end up with four renderings and that's if you have just two categories
of shapes and to render.
If you have three shapes and three different renderings Well you've got nine different objects.
So that's what we want to try to avoid.
And the way this is done is by once again defining interfaces and defining that bridge as a kind of
reference.
I remember when we talked about the pimple.
You basically have a type and that type has a pointer to whatever the implementation is so that would
be the bridge and we're going to do something similar here.
So to begin with I'm going to define a structure called a render.
So a renderer obviously has to be able to render different shapes and we're only going to have one shape
I'll just stick to a circle.
But you can sort of assume that there are other shapes out there so I'll have a virtual void function
called rendah circle.
And you can define the x and y coordinates which would be the center of the circle so flow tax float
Y.
And also the radius of the circle.
And that would be a pure virtual member function.
So essentially you want to implement different renderers like for example you want the vector renderer
as well as a roster renderer.
So here I can make a structure called vector renderer which will be a renderer.
Once again lets go and implement the appropriate function.
So here we have rendah circle in vector form so I can for example see out that we are bastardising a
circle of radius and I'll just output the radius.
I want to touch the x and y coordinates like so.
And in addition you can also have let's say a roster renderer is around there that we go.
So once again go into the implementation.
Implement the whole thing and then we're going to see something different.
So this time round we're going to say that we're drawing a vector a circle of radius.
And once again putting the radius here followed by an end line so this is how you have different rendering
implementations.
So we haven't really made circles or indeed any kind of shapes yet so that's what we're going to do
now.
So I wanted to define this idea of a shape.
We go now inside the shape what I want to do is I want to have a reference to the kind of rendering
that we're going to be doing.
So I want to reference to the renderer and that is in fact going to be our bridge So essentially we
have this bridge to the Rander that's being applied to this particular shape.
So here I have a protected section and I'll have a render a reference.
And in addition I'll have a constructor not a test a constructor which actually initializes this reference.
There we go.
Now the constructor is also going to be protected.
We can sort of override it later on and then we'll have a bunch of public grammar rules so we might
have a pure virtual function called draw for actually drawing the shape and we might also have other
kind of abstractions specific functions like for example unknowables you to resize the shape so you'll
have virtual void resize taking some factor.
And that's also going to be a pure virtual function.
All right so now that you have this shape with the bridge in place what you can do is you can actually
inherit from it so you can make a circle for example and the circle is going to be a shape.
So we'll have the circle parameters like the X the y coordinates as well as the radius of the circle.
We'll also have a constructor you can already see the red wavy underline saying that we need a constructor.
So I'll generate one that looks like this.
But of course I also want to initialize the X the Y and the radius as well so I'll have those here.
Like so and after we called the base constructor what I'll do is I'll initialize the the x the Y and
the radius would go OK.
So this is my initialization code that can make it a little bit more readable this way.
And also I want to be able to draw the circle as well as resize it.
So let's implement those members once again.
Very helpful cogeneration mechanism here.
So for the drawing that's the fun part.
We'll get to that drawing in just a moment.
The resizing is easy here so I can just multiply the radius by whatever factor is being specified.
Now the drawing is the fun part.
So remember we have a circle which inherits from shape and as a result it inherits this reference to
the bridge that allows us to render the circle in a variety of ways we can render it as a vector object
or as a set of pixels.
So here what we do is we actually use this bridge so we say render a dot and we render the circle we
can provide the X the Y and the radius.
And of course this parameter which is actually passed in here can be either a vector renderer or a ROS
to render or if you decide to expand your model it can be some other rendah Rosewell.
So having put all of this together we can now actually start using this API.
So let's suppose you want to make a circle.
So you want to make a circle called circle and let's suppose we decide to use the roster form.
So we want the circle represented this pixel so I'll call this a roster circle.
And here the first argument has to be a roster renderer obviously so that is the bridge that you'd make.
So you'd make a roster renderer are like so and you would pass that in and then you would pass in the
X the Y as well as the radio.
So just keep them all the same here.
So we can take the circle and we can draw this so we can fold draw and then we can also resize it and
draw it again.
So here I can see Erastus call Dalt resize multiplied by a factor of two and then draw it again.
So this is our implementation Let's actually execute this and see what we get as we run this fairly
obvious stuff here since we're using our Rosse to render it should render the pixels for a radius of
five and then render the pixels for a radius of 10 and that's exactly what we're getting.
So here we are drawing.
Surprisingly enough we're drawing a vector circle.
Let me actually just verify that I haven't mixed those up.
Yes.
So these should be the other way round actually so it should be this one should be the vector Endora
and this one should be the roster render but hopefully you see the idea.
So essentially what we're doing is we're defining this hierarchy of interfaces which can be fed as a
bridge into whatever component is actually using it.
So instead of spawning for different renderers like square a roster render a square vector and where
and so on and so forth for each shape what we're doing is we're passing it in as a constructor argument.
We're holding onto that reference.
And whenever we come to actually draw the particular shape we use that bridge to draw it in the suitable
format.