Mar 24th, 2023
The Bridge Pattern is a structural design pattern that decouples an abstraction from its implementation, allowing them to vary independently. This pattern is useful when we want to separate the abstraction from its implementation so that they can be modified independently without affecting each other.
In the Bridge Pattern, we create two separate hierarchies, one for the abstraction and one for the implementation. The abstraction defines the high-level functionality, while the implementation provides the low-level details. The two hierarchies are then linked through a bridge object, which allows the abstraction to delegate to the implementation.
Let's consider an example of a shape hierarchy that has different types of shapes such as circle, square, and rectangle, and different drawing implementations such as raster and vector. We can use the Bridge Pattern to decouple the shape hierarchy from the drawing implementation hierarchy.
To implement the Bridge Pattern, we need to define an abstraction interface that defines the high-level functionality and a separate implementation interface that provides the low-level details. We then create concrete classes for the abstraction and the implementation, which can vary independently. Finally, we create a bridge class that links the abstraction and implementation together.
Here's an example code snippet that demonstrates the Bridge Pattern:
// Abstraction interface interface Shape { public void draw(); } // Concrete classes for abstraction class Circle implements Shape { private DrawingAPI drawingAPI; private double x, y, radius; public Circle(double x, double y, double radius, DrawingAPI drawingAPI) { this.x = x; this.y = y; this.radius = radius; this.drawingAPI = drawingAPI; } public void draw() { drawingAPI.drawCircle(x, y, radius); } } class Square implements Shape { private DrawingAPI drawingAPI; private double x, y, side; public Square(double x, double y, double side, DrawingAPI drawingAPI) { this.x = x; this.y = y; this.side = side; this.drawingAPI = drawingAPI; } public void draw() { drawingAPI.drawSquare(x, y, side); } } // Implementation interface interface DrawingAPI { public void drawCircle(double x, double y, double radius); public void drawSquare(double x, double y, double side); } // Concrete classes for implementation class RasterDrawingAPI implements DrawingAPI { public void drawCircle(double x, double y, double radius) { // draw circle using raster graphics } public void drawSquare(double x, double y, double side) { // draw square using raster graphics } } class VectorDrawingAPI implements DrawingAPI { public void drawCircle(double x, double y, double radius) { // draw circle using vector graphics } public void drawSquare(double x, double y, double side) { // draw square using vector graphics } } // Client code public class Client { public static void main(String[] args) { Shape circle = new Circle(1, 2, 3, new VectorDrawingAPI()); circle.draw(); Shape square = new Square(4, 5, 6, new RasterDrawingAPI()); square.draw(); } }
In this example, we have an abstraction interface Shape
and two concrete classes Circle
and Square
that implement the interface. We also have an implementation interface DrawingAPI
and two concrete classes RasterDrawingAPI
and VectorDrawingAPI
that implement the interface.
We create a bridge object by passing the DrawingAPI
object to the Circle
and Square
constructors. The draw() method of the Circle and Square classes then delegates to the drawCircle() and drawSquare() methods of the DrawingAPI object respectively.
The Client
class demonstrates how to use the bridge object to create different shapes with different drawing implementations. In this example, we create a Circle
object with VectorDrawingAPI
and a Square
object with RasterDrawingAPI
.
By using the Bridge Pattern, we can decouple the shape hierarchy from the drawing implementation hierarchy, allowing them to vary independently. This makes it easier to modify and extend both hierarchies without affecting each other.
In conclusion, the Bridge Pattern is a powerful structural design pattern that allows us to decouple abstractions from their implementations, making it easier to modify and extend them independently. By using the Bridge Pattern, we can improve the flexibility and maintainability of our code.