- 1. Goals
- 2. Problems
- 3. Motivation
- 4. Discussion
- 5. Structure
- 6. Example
- 7. Control List
- 8. Rules of thumb
Goals
- Separate the abstraction from its implementation so that they can change independently of each other.
- Create a public interface in an inheritance hierarchy and implement it in your own inheritance hierarchy.
- In addition to encapsulation, the use of isolation
Problems
"Strengthening programming relationships" by using a subclass of an abstract base class to provide alternative implementations. This blocks compile-time binding between interface and implementation. Abstraction and implementation cannot be independently extended or redefined.
Motivation
Consider the area of "thread scheduling".
There are two types of thread schedulers, two types of operating systems or "platforms". Given this approach to specialization, we must define a class for each of these two variations. If we add a new platform (say... the Java Virtual Machine), what would our hierarchy look like?
What if we had three kinds of thread schedulers and four kinds of platforms? What if we had five types of thread schedulers and ten types of platforms? The number of classes we would have to define is the result of the number of scheduling schemes and the number of platforms.
The Bridge design pattern suggests refactoring this exponentially explosive inheritance hierarchy into two orthogonal hierarchies - one for platform-independent abstractions and one for platform-dependent implementations.
Discussion
Decompose the component's interface and implementation into orthogonal class hierarchies. An interface class contains a pointer to an abstract implementation class. This pointer is initialized with an instance of the concrete class, but all subsequent interaction of the interface class with the implementation class is limited to the abstraction supported in the base implementation class. The client interacts with the interface class and in turn "delegates" all requests to the class implementation.
The interface object is the "handler" known and used by the client; while the implementation object or "body" is safely encapsulated to ensure that it can continue to evolve or be completely replaced (or used at runtime.
Use the Bridge pattern if:
- You want the implementation to bind at runtime
- you have an increase in the number of classes resulting from a coupled interface and multiple implementations,
- you want to share the implementation among several objects,
- you need to map orthogonal class hierarchies.
Consequences include:
- object interface decomposition
- improved extensibility (you can extend (e.g. subclass) abstraction and implementation hierarchies independently),
- hiding details from customers.
Bridge is synonymous with the handler/body idiom. It is a design mechanism that encapsulates an implementation class within an interface class. The first is the body and the second is the handler. The handler is treated by the user as an actual class, but the work is done in the body. “The handle/body class idiom can be used to decompose a complex abstraction into smaller, more manageable classes. The idiom can reflect the sharing of a single resource by multiple classes that control access to it (for example, reference counting)."
Structure
The client doesn't want to deal with platform dependent details. The Bridge pattern encapsulates this complexity behind an abstract wrapper.
Bridge emphasizes the identification and separation of the "interface" abstraction from the "implementation" abstraction.
Example
The Bridge pattern separates the abstraction from its implementation so that they can vary independently. An example of a Bridge is a household switch that controls lights, ceiling fans, etc. The purpose of a switch is to turn a device on or off. In fact, the switch can be implemented as a pull chain, a simple on/off switch, or various dimmer switches.
Control List
- Decide if there are two possible orthogonal class hierarchies in the application. These independent hierarchies can be: abstraction/platform, or domain/infrastructure, or interface/interface, or interface/implementation.
- Develop a separation of concerns: what the client wants and what the platforms provide.
- Create a platform interface that is minimal, necessary and sufficient. Its purpose is to separate the abstraction from the platform.
- Define a derived class of this interface for each platform.
- Create a base abstraction class that has a "platform object" and delegates platform-specific functionality to it.
- Define abstraction class specializations, if necessary.
Rules of thumb
- The adapter allows you to work with classes after they are developed; The bridge makes them work before they were designed.
- The bridge is designed in advance so that the abstraction and implementation change independently. The adapter modernizes the code so that the classes work together.
- State, Strategy, Bridge (and to some extent Adapter) have similar decision structures. They all share elements of the handler/body idiom. They differ in intent - that is, they solve different problems.
- The structure of State and Bridge is identical (except that Bridge allows class hierarchies, while State only allows one). The two patterns use the same structure to solve different problems: State allows the behavior of an object to change along with its state, while the intent of the Bridge is to separate the abstraction from its implementation so that they can vary independently.
- If class interfaces delegate the creation of their implementation classes (instead of directly creating/binding themselves), then the project typically uses the Abstract Factory pattern to create implementations of the objects.