Summary
While reviewing the Bridge pattern, I looked at a problem where there were two variations in the problem domain—shapes and drawing programs. In the problem domain, each of these varied. The challenge came when trying to implement a solution based on all the special cases that existed. The initial solution, which naively used inheritance too much, resulted in a redundant design that had tight coupling and weak cohesion, and was thus difficult to maintain.
You learned the Bridge pattern by following the basic strategies for dealing with variation:
- Find what varies and encapsulate it.
- Favor aggregation over inheritance.
Finding what varies is always a good step in learning about the problem domain. In the drawing program example, I had one set of variations using another set of variations. This indicates that the Bridge pattern will probably be useful.
In general, you should identify which patterns to consider by matching them with the characteristics and behaviors in the problem domain. By understanding the whys and whats of the patterns in your repertoire, you can be more effective in picking the ones that will help you. You can select patterns to consider before deciding how the pattern’s implementation will be done.
If you use9 the Bridge pattern, the design and implementation are more robust and better able to handle changes in the future.
Although I focused on the Bridge pattern during the chapter, it is worth pointing out several object-oriented principles that are used in the Bridge pattern.
Concept |
Discussion |
Objects are responsible for themselves |
I had different kinds of Shapes, but all drew themselves (via the draw method). The Drawing classes were responsible for drawing elements of objects. |
Abstract class |
I used abstract classes to represent the concepts. I actually had rectangles and circles in the problem domain. The concept “shape” is something that lives strictly in our head, a device to bind the two concepts together; therefore, I represent it in the Shape class as an abstract class. Shape will never get instantiated because it never exists in the problem domain (only Rectangles and Circles do). The same thing is true with drawing programs. |
Encapsulation via an abstract class |
I have two examples of encapsulation through the use of an abstract class in this problem:
|
One rule, one place |
The abstract class often has the methods that actually use the implementation objects. The subclasses of the abstract class call these methods. This allows for easier modification if needed, and allows for a good starting point even before implementing the entire pattern. |
Testability |
Imagine writing tests for the shapes and drawing programs with both our original solution and our later solution. For example, suppose you have N shapes and M implementations. The first solution would require N*M tests. The second solution only requires M+N tests: First test the M implementations, and then test the N shapes with arbitrarily chosen implementations (because all of the shapes work with all of the implementors in exactly the same way). |