Introducing the Bridge design pattern

Introducing the Bridge design pattern

Read Time : 3 Minutes

Tuesday, 11 April 2023

Design patterns are proven solutions to software design problems. They help improve code quality, promote reusability, and increase maintainability. We use them to save time and produce quality, extensible and flexible code. In this article, we are going to introduce the Bridge design pattern.

The Bridge pattern is a structural design pattern that separates abstractions from implementations so that they can be independent. This pattern allows for greater flexibility and interchangeability between different implementations of an abstraction.

In this pattern, there are two distinct hierarchies: an abstraction hierarchy and an implementation hierarchy. The interface abstraction hierarchy defines the top level that client code uses to interact with the abstraction, while the implementation hierarchy provides the concrete entities of the same abstraction.

bridge pattern

The Bridge pattern is useful when there are multiple implementations of the same abstraction and we want to change them at runtime without affecting the client code. By separating the abstraction and implementation hierarchies, the Bridge pattern helps reduce dependencies between components and making it easier to maintain and modify both hierarchies independently.

Below is an example of how to implement the Bridge pattern in C#:

// Abstraction
public abstract class Shape
{
    protected IRenderer renderer;
   
    public Shape(IRenderer renderer)
    {
        this.renderer = renderer;
    }
    public abstract void Draw();
}
public class Circle : Shape
{
    private float radius;
    public Circle(IRenderer renderer, float radius) : base(renderer)
    {
        this.radius = radius;
    }
    public override void Draw()
    {
       renderer.RenderCircle(radius);
    }
}
public class Square : Shape
{
    private float side;
    public Square(IRenderer renderer, float side) : base(renderer)
    {
        this.side = side;
    }
    public override void Draw()
    {
       renderer.RenderSquare(side);
    }
}
// Implementation
public interface IRenderer
{
    void RenderCircle(float radius);
    void RenderSquare(float side);
}
// Concrete Implementation
public class VectorRenderer : IRenderer
{
    public void RenderCircle(float radius)
    {
       Console.WriteLine($"Drawing a circle of radius {radius} using vector graphics.");
    }
    public void RenderSquare(float side)
    {
       Console.WriteLine($"Drawing a square of side {side} using vector graphics.");
    }
}
// Concrete Implementation
public class RasterRenderer : IRenderer
{
    public void RenderCircle(float radius)
    {
       Console.WriteLine($"Drawing a circle of radius {radius} using raster graphics.");
    }
    public void RenderSquare(float side)
    {
        Console.WriteLine($"Drawing a square of side {side} using raster graphics.");
    }
}
// Client code
var vectorCircle = new Circle(new VectorRenderer(), 5);
vectorCircle.Draw(); // Output: Drawing a circle of radius 5 using vector graphics.
var rasterSquare = new Square(new RasterRenderer(), 10);
rasterSquare.Draw(); // Output: Drawing a square of side 10 using raster graphics.

In this example, the Shape class is abstract and has Circle and Square derivatives. The IRenderer interface is the implementation part and has two main implementations, VectorRenderer and RasterRenderer. The Shape class takes an IRenderer object in its constructor and uses it to execute the shape drawing command in its respective implementations. Client code can create different forms with different implementations at runtime, without requiring code changes.

To read about other design patterns, you can use the list below. There is also a code repository on GitHub that includes all the design patterns.

design patterns

Creational:Factory Design Pattern
Builder Design Pattern
Singleton Design Pattern
Prototype Design Pattern
Abstract Factory Design Pattern
Structural:Adapter Design Pattern
Bridge Design Pattern
Composite Design Pattern
Decorator Design Pattern
Facade Design Pattern
Flyweight Design Pattern
Proxy Design Pattern
Behavioral:Chain of Responsibility Design Pattern
Command Design Pattern
Interpreter Design Pattern
Mediator Design Pattern
Memento Design Pattern
Observer Design Pattern
State Design Pattern
Strategy Design Pattern
Template Method Design Pattern
Visitor Design Pattern
Iterator Design Pattern
  • Share:
reza babakhani
Reza Babakhani

I am Reza Babakhani, a software developer. Here I write my experiences, opinions and suggestions about technology. I hope that what I write is useful for you.

Latest post

Service Mesh Simplifying Microservice Communication

In the ever-evolving landscape of software development, microservices architecture has gained considerable popularity due to its scalability, flexibility, and extensibility. However, as the number of microservices in an application increases, it becomes increasingly challenging to manage their communication and ensure that they are all properly visible. This is where Service Mesh comes into play.

The Importance of Edge Computing

Due to the speed of technological evolution, one of the concepts that has attracted a lot of attention and changes the way we interact with digital systems is edge computing.

What is event-driven architecture?

Event-driven architecture (EDA) is a software design pattern that has become increasingly popular in modern software development. In this architecture, the flow of data is determined by the occurrence of events. Unlike traditional centralized systems that are constantly checking for new status. Event-driven architecture is especially useful for systems that need to process large amounts of data in real-time.

leave a comment