Lecture thumbnail 0:02 / 9:49 The bridge pattern simply allows you to connect different abstractions together, and there is nothing

particularly magical or even interesting about the bridge pattern.

So we’re going to restrict ourselves to just a single example of the bridge pattern.

And let me show you what we can do now.

I’m going to pretend that we’re going to be rendering objects, and there are different ways of rendering

an object.

You can do a vector way of rendering an object where an object is presented in vector form, or you

can do it using pixels, the kind of rasterized form.

And we’re not even going to do those in real life.

We’re just going to emulate both of them.

But the idea is that we’re doing rendering, so we may as well have an interface called I renderer and

it’s going to have a single method for, let’s say, rendering a circle so we have void render circle

of a certain radius.

There we go.

So that’s the interface.

And then we have different renderers, like you can have, for example, a vector renderer.

So a vector renderer can be an AI renderer, AI renderer.

And if we implement this, I’ll just write a line that we are drawing a circle of radius and then specify

the radius here like so.

And in addition, we’ll do the same for, let’s say, the raster renderer, also an AI renderer.

I render like so implement the interface and here I’ll write line that we’re drawing pixels for circle

with radius and then specify the radius.

You can also specify other information like the x y coordinates where you want to draw the circle.

I’m just ignoring this for the sake of simplicity.

So now let’s talk about the different shapes that you want to draw.

So a circle is only one example of a shape.

So you can have some sort of abstract hierarchy where you have an abstract class called shape.

Now here is where the bridging happens.

So what you can do is instead of specifying that the shape is able to draw itself as either a raster

form or a some other form, you don’t put this limitation in place so you don’t let shape decide the

different ways in which it can be drawn.

Instead, all you have to do is you have to build a bridge between the shape and whoever is drawing

it, which is an AI renderer.

Okay.

So that’s exactly what we’re going to do and we’ll just do it using constructor injection.

So here I’ll have I’ll have protected my renderer renderer and we will make the initialization of this

in the constructor like so let me also join the null check and the assignment here.

And in addition, we’re going to have a few methods on the shape.

So what can you do with the shape?

Now remember, we’re not specifying in the shape itself whether we want to render it in a raster form

or in vector form.

Instead, we’re saying, please just render it however you specify.

So we’re going to have an abstract, not an abstract class, but we’re going to have an abstract method.

So we’re going to have public abstract void draw and we’ll also have a method for resizing the shape.

So let’s have resize.

Okay, so I’m going to resize and we will specify the factor by which we want to resize this particular

shape.

And then of course we can implement an actual shape like a circle, for example.

And a circle is obviously inheriting from shape here.

So that’s what we’re going to do and we will implement the missing members here.

Okay, So we have the draw method as well as the resize method.

And here all that we do is we use that bridge.

So we have this eye renderer interface and we can invoke this interface to actually draw the circle.

So in addition, just before we do this, I’ll add a radius field, so float radius like so, and then

we’ll do the constructor C to r F to initialize all the fields.

And that includes calling the base class constructor with the AI renderer, of course.

And then when it comes to drawing, because we made the renderer protected and not private, we can

actually use it to draw the circle in whatever other form we want.

So we basically say renderer dot render circle and we specify the radius and the same goes for the resize.

Except that well, we don’t need the renderer for this one.

We can just have radius multiplied by some factor and this is done so that we can show that changes

to the radius actually affect the way that it gets rendered, which is fairly obvious stuff.

So having built all of this, we can now try and actually using it.

So typically you make a circle, var circle equals new circle and you look at the constructor arguments

and you realize that you have to specify not just the radius, but also the renderer renderer as well

as the radius.

Let’s have it as five for example.

So the render has to be created.

Let’s make a local variable and I will assign it to a new raster renderer, for example.

So now that we have this, there is this connection between the circle that we’ve just made and the

rendering mechanism that we’ve specified so we can take the circle and we can, for example, draw circle,

dot draw, just draw the circle, and then we can try resizing the circle by a factor of two and drawing

it again.

There we go.

So this is how you essentially build a bridge and now we’re going to see the results of our work.

So here we go.

We’re drawing pixels for the circle with radius five and then drawing pixels for the circle with radius

ten.

Now what we can do is we can substitute, we can have a different AI renderer.

So here I can say var renderer equals new vector renderer and this time round, fairly obvious stuff.

We’re just drawing a circle without drawing the pixels.

So we’re drawing a circle with radius five and then we double the radius and we’re drawing a circle

which is bigger.

Okay, so this is how you can implement the bridge pattern.

And in addition to what we’ve just implemented here, you would typically once again, you would probably

go ahead and have that injection defined somewhere in a dependency injection container because having

to pass the renderer, if you have, let’s say, 100 objects, is a bit tedious.

I mean, you can do it, but if you are using dependency injection, it’s a lot easier.

So let’s try that instead.

So I’ll make a container builder.

I’m using Autofac once again, so I’ll make a container builder like so.

And here I will first of all register the renderer that I want.

So I will say, for example, that I will register the vector renderer as an eye renderer, like so

I don’t know where the space came from.

So this is basically saying that any time somebody asks for an eye renderer, you have to inject a vector

renderer.

Okay, so having made this and by the way, you just need one renderer for all the objects, you can

also put a dot here and make it a singleton by calling single instance.

And then what we do is we register the circle.

But the circle is a bit tricky.

The circle is tricky because on the one hand it depends on the eye renderer, which we can inject.

On the other hand, it takes an argument and maybe we want to specify that argument where we actually

resolve the circle from the container.

So the way this is done is a bit tedious, but let’s do it.

So we call the function register and here is the context and the parameter stuff.

And we return a new circle, new circle like this.

So the first part, which is the eye renderer, is easy to inject because you simply say context, dot

resolve, just resolve without the component resolve eye renderer.

And that’s pretty much it.

So this is how you get the first argument in there.

Now the second argument, which is the radius, is something you want to provide later on, not at the

point where you configure the container, but actually when you already made the container and you’re

resolving components from it.

So in this case, all we do is we say, Oh, there is a positional argument here.

You can also have a named argument, by the way, if you want, I’ll just do positional.

So there’s a positional argument here of type float.

It’s at position zero and that’s it.

We are now ready to actually build the container and then start using.

And so let’s try it using var C equals Sbuild.

So we build the container and now what we do is we make a circle.

And the way we do it and I’ll say circle here is as follows We take the container and we resolve a circle.

But here’s the thing.

We have to provide that argument.

And remember, we chose to make those arguments positional.

So in this case, we say new new positional parameter, new positional parameter with position zero

and the value of 5.0.

And by the way, if you just put a five in here, it’s not going to work because in this particular

case there is no automatic conversion from INT to float.

So it’s just going to throw an exception.

So 5.0 if you have to be precise about this.

And then once again, we can do the things that we’ve done previously.

So you can do circle dot draw and then you can resize and then draw again.

So circle dot resize 2.0 F and once again we can execute all of this.

And as you can see, we’re getting exactly the same results.

So the takeaway from this is that the bridge pattern is really nothing more than a way of connecting

a part of a system.

So we have a circle as a domain object and you’re connecting that domain object to the different implementation

of the rendering mechanism and you’re doing it Non-intrusively So instead of giving a circle methods

for drawing in raster form and drawing in vector form, you basically providing it this eye renderer

and thereby making the bridge between the domain object and the way this object should be processed.

Play Stop Start Play information alert