When to use
- When run-time binding of the implementation is required.
- To support a proliferation of classes resulting from a coupled interface and numerous implementations,
- To share an implementation among multiple objects and to map orthogonal class hierarchies.
Intent
- Decouple an abstraction from its implementation so that the two can vary independently.
Structure
Implementation
The Bridge pattern is an application of the old advice, "prefer composition over inheritance". It becomes handy when you must subclass different times in ways that are orthogonal with one another. Say you must implement a hierarchy of colored shapes. You wouldn't want to subclass Shape with Rectangle and Circle and then subclass Rectangle with RedRectangle, BlueRectangle and GreenRectangle and the same for Circle. You would prefer to say that each Shape has a Color and to implement a hierarchy of colors, and that is the Bridge Pattern.
1 Design a color-oriented interface that is minimal, necessary, and sufficient. Its goal is to decouple the abstraction from the color. Define a derived class of that interface for each color.
package com.gaurav.dp.bridge;
public interface Color {
void applyColor();
}
2 Define a derived class of that interface for each color.
package com.gaurav.dp.bridge;
public class Red implements Color {
public void applyColor() {
System.out.println("Red");
}
}
package com.gaurav.dp.bridge;
public class Green implements Color {
public void applyColor() {
System.out.println("Green");
}
}
3 Create the abstraction base class that "has a" color object and delegates the color-oriented functionality to it.
package com.gaurav.dp.bridge;
public abstract class Shape {
protected Color color;
public Shape(Color c) {
color = c;
}
public abstract void draw();
}
4 Define specializations of the abstraction class.
package com.gaurav.dp.bridge;
public class Circle extends Shape {
public Circle(Color color) {
super(color);
}
public void draw() {
System.out.print("Draw Circle in ");
color.applyColor();
}
}
package com.gaurav.dp.bridge;
public class Rectangle extends Shape {
public Rectangle(Color color) {
super(color);
}
public void draw() {
System.out.print("Draw Rectangle in ");
color.applyColor();
}
}
package com.gaurav.dp.bridge;
public class Square extends Shape {
public Square(Color color) {
super(color);
}
public void draw() {
System.out.print("Draw Square in ");
color.applyColor();
}
}
5 The Client code. The Bridge Pattern allows one to mix and match without needing to create a rigid hierarchy.
package com.gaurav.dp.client;
import com.gaurav.dp.bridge.Circle;
import com.gaurav.dp.bridge.Green;
import com.gaurav.dp.bridge.Rectangle;
import com.gaurav.dp.bridge.Red;
import com.gaurav.dp.bridge.Shape;
import com.gaurav.dp.bridge.Square;
public class BridgeClient {
public static void main(String[] args) {
Shape[] shapes = {
new Circle(new Red()),
new Square(new Red()),
new Rectangle(new Green())
};
for (Shape shape : shapes) {
shape.draw();
}
}
}
Output
[output]
Draw Circle in Red
Draw Square in Red
Draw Rectangle in Green
Benefits
- Decoupling allows us to choose the implementations at runtime.
- Compile-time dependencies on the implementation are eliminated.
- Improved extensibility and flexibility.
Drawbacks
- The delegation from the Entities to the Behaviors can degrade performance.
Real World Examples
- The display of different image formats on different operating systems is a good example of the Bridge pattern. You might have different image abstractions for both jpeg and png images. The image structure is the same across all operating systems, but the how it's viewed (the implementation) is different on each OS. This is the type of decoupling that the Bridge pattern allows.
Software Examples
- UnifiedPOS or UPOS that provides vendor-neutral APIs for numerous Point Of Sale peripherals.
- OS specific Device Driver interfaces that define common standards for various devices.
Top comments (0)