Join Jungwoo Ryoo for an in-depth discussion in this video Bridge example, part of Design Patterns with Python.
- Let's go ahead and define our implementation specific classes. The first one is DrawingAPIOne. It has a method called draw circle and it's accepting three arguments, x coordinate, y coordinate, and then the radius. And then it simply prints a message saying API 1 drawing a circle at coordinate x, y with radius. So there's another implementation specific class we need to define, in this case, DrawingAPITwo.
We will start with the method, def. And then the name of the method, draw_circle. Argument, self, x, y, radius. So the interface is the same, however, the implementation will be different. Print. The difference in the implementation in this case lies in the difference in the message. So it'll be the same message except for this part, we'll say API 2 drawing a circle.
Now let's define our implementation, independent class, which is circle. How to draw a circle is implementation dependent, but there are things that are implementation independent in terms of defining a circle. So the very first part of this circle class definition is initializing its attributes. So we have x coordinate being initialized, y, and then the radius.
And finally we have the last argument, which is drawing_api. This is the argument that's accepting an instance of our drawing API 1 or 2 classes. So these attributes are, of course, implementation independent. However, when it comes to drawing or how to draw these circles, is implementation dependent. And that's really dependent on the last argument we're accepting.
So we will be using it. We will type self_drawing_api, which is the attribute containing our object, especially the drawing_api object, and then we'll invoke draw_circle method, and then we'll be passing our arguments based on what we just received. So self._x, self._y and then finally, self._radius.
These are all the values stored in our attributes. Again, the next method, scale, is implementation independent because scaling a circle, whether it's bigger or smaller, has nothing to do with how to implement the circle. So after defining these classes, now we are ready to actually create a circle object. So we use the circle class, as you can see here, and we pass our arguments.
But in the argument list, the most important one is DrawingAPIOne because this decides what kind of implementation we're using to draw a circle. And then once we are done, we're invoking the draw method on the circle object. So we'll be doing the same thing for the second circle, so we'll just type circle2, assignment, Circle, x coordinate is 2, y coordinate is 3, and the radius is 4.
And we'll be using a different implementation method this time, DrawingAPITwo, and then, finally, we'll invoke the draw method on circle2. Let's run the code. Go to Tools, click on Build. And as you can see, the code worked. One thing you really have to remember about this pattern, the bridge pattern, is that it is very useful, especially when you have so many different kinds of classes involved in your hierarchy, sometimes it makes much more sense to separate these classes into different hierarchies.
- Understanding design patterns
- Best design practices: consistency, completeness, and correctness
- Working with creational patterns
- Working with structural patterns
- Working with behavioral patterns
Skill Level Intermediate
Q: In the strategy pattern example, why does the code keep executing the default function rather than the alternate?
A: The programming demonstration skips the step of defining what the strategy pattern should be when an alternate function name is provided
as an argument as shown below.