The Bridge Design Pattern is a structural pattern that separates the abstraction from its implementation so that the two can vary independently.This pattern involves an interface that acts as a bridge between the abstraction class and implementer classes. It is useful in scenarios where an abstraction can have several implementations, and you want to separate the implementation details from the abstraction.
Related Articles
Purpose of Bridge Pattern
- Decouple an abstraction from its implementation so that the two can vary independently.
- Promote code reusability by allowing the abstraction and implementation to evolve independently.
In the Bridge Design Pattern, there are 2 parts. The first part is the Abstraction, and the second part is the Implementation. The Bridge Design Pattern allows both Abstraction and Implementation to be developed independently, and the client code can only access the Abstraction part without being concerned about the Implementation part.
Components of Bridge Design Pattern:
- Abstraction: This is an abstract class and containing members that define an abstract business object and its functionality. It contains a reference to an object of type Bridge. It can also act as the base class for other abstractions.
- Refined Abstraction: This is a class which inherits from the Abstraction class. It extends the interface defined by Abstraction class.
- Implementor(Bridge): This is an interface which acts as a bridge between the abstraction class and implementer classes and also makes the functionality of implementer class independent from the abstraction class.
- Concrete Implementor: These are classes which implement the Bridge interface and also provide the implementation details for the associated Abstraction class.
Example in C#:
Let's consider a scenario where we have different shapes, and each shape can be drawn using different drawing engines. We'll implement the Bridge Pattern to achieve the separation of abstraction (shape) and implementation (drawing engine).
Create Bridge Interface(IDrawingEngine.cs):namespace BridgePattern.BridgeInterface { ///Create Concrete Implementors(DrawingEngineA.cs and DrawingEngineB.cs): DrawingEngineA.cs/// Bridge Interface /// public interface IDrawingEngine { void DrawCircle(int radius, int x, int y); void DrawSquare(int side, int x, int y); } }
using BridgePattern.BridgeInterface; namespace BridgePattern.Implementor { ///DrawingEngineB.cs/// Concrete Implementors /// public class DrawingEngineA : IDrawingEngine { public void DrawCircle(int radius, int x, int y) { Console.WriteLine($"Drawing Circle with Engine A: Radius={radius}, X={x}, Y={y}"); } public void DrawSquare(int side, int x, int y) { Console.WriteLine($"Drawing Square with Engine A: Side={side}, X={x}, Y={y}"); } } }
using BridgePattern.BridgeInterface; namespace BridgePattern.Implementor { ///Create Abstraction Class(Shape.cs):/// Concrete Implementors /// public class DrawingEngineB : IDrawingEngine { public void DrawCircle(int radius, int x, int y) { Console.WriteLine($"Drawing Circle with Engine B: Radius={radius}, X={x}, Y={y}"); } public void DrawSquare(int side, int x, int y) { Console.WriteLine($"Drawing Square with Engine B: Side={side}, X={x}, Y={y}"); } } }
using BridgePattern.BridgeInterface; namespace BridgePattern.Abstraction { ///Create Refined Abstraction(Square.cs and Circle.cs): Square.cs/// Abstraction Class /// public abstract class Shape { protected IDrawingEngine drawingEngine; protected Shape(IDrawingEngine drawingEngine) { this.drawingEngine = drawingEngine; } public abstract void Draw(); } }
using BridgePattern.Abstraction; using BridgePattern.BridgeInterface; namespace BridgePattern.RefinedAbstractions { ///Circle.cs/// Refined Abstractions /// public class Square : Shape { private int side; private int x; private int y; public Square(int side, int x, int y, IDrawingEngine drawingEngine) : base(drawingEngine) { this.side = side; this.x = x; this.y = y; } public override void Draw() { drawingEngine.DrawSquare(side, x, y); } } }
using BridgePattern.Abstraction; using BridgePattern.BridgeInterface; namespace BridgePattern.RefinedAbstractions { ///Client Code(Program.cs):/// Refined Abstractions /// public class Circle : Shape { private int radius; private int x; private int y; public Circle(int radius, int x, int y, IDrawingEngine drawingEngine) : base(drawingEngine) { this.radius = radius; this.x = x; this.y = y; } public override void Draw() { drawingEngine.DrawCircle(radius, x, y); } } }
using BridgePattern.Abstraction; using BridgePattern.BridgeInterface; using BridgePattern.Implementor; using BridgePattern.RefinedAbstractions; IDrawingEngine engineA = new DrawingEngineA(); IDrawingEngine engineB = new DrawingEngineB(); Shape circleA = new Circle(5, 10, 15, engineA); Shape squareB = new Square(8, 20, 25, engineB); circleA.Draw(); squareB.Draw(); Console.ReadLine();
Output
In the above example, Shape is the abstraction, and IDrawingEngine is the implementor(bridge) interface. Concrete implementations of the drawing engines are DrawingEngineA and DrawingEngineB. The Circle and Square classes are refined abstractions that extend the basic interface provided by the Shape class.
By using the Bridge Design Pattern, we can easily switch drawing engines for different shapes without modifying the shape classes, promoting flexibility and maintainability in our code.
The full source code is available here:
Happy coding!! 😊