Open In App

Bridge Method | C++ Design Patterns

Bridge Pattern is basically a structural design pattern in software engineering or in C++ programming that is used to separate an object’s abstraction from its implementation. It is part of the Gang of Four (GoF) design patterns and is particularly useful when we need to avoid a permanent binding between an abstraction and its implementation. The Bridge Pattern promotes flexibility and allows us to change both the abstraction and the implementation independently.

Use Cases of the Bridge Pattern in C++ Design Patterns

Example for Bridge Design Pattern in C++:

Let’s assume that if we want to create a drawing program where we have different shapes (e.g., circles and squares) and different rendering methods (e.g., vector and raster). The Bridge pattern can help us to separate the shapes (abstraction) from the rendering methods (implementation).

Implementation of Bridge Pattern in C++:

Abstraction:

Shape (Abstract Class) is defined as an abstract class with a pure virtual function draw(). This represents the abstraction part of the Bridge Pattern.






// Abstraction: Shape
class Shape {
public:
    virtual void draw() = 0;
};

Renderer is another abstract class with a pure virtual function render(). This represents the implementation part of the Bridge Pattern.




// Implementations: Renderer (VectorRenderer and RasterRenderer)
class Renderer {
public:
    virtual void render() = 0;
};
 
class VectorRenderer : public Renderer {
public:
    void render() override {
        std::cout << "Rendering as a vector\n";
    }
};
 
class RasterRenderer : public Renderer {
public:
    void render() override {
        std::cout << "Rendering as a raster\n";
    }
};

Concrete Abstractions:

Circle and Square are concrete shape classes derived from the Shape abstract class.They each have a member of type Renderer to hold a reference to the renderer implementation.Circle and Square are concrete shape classes derived from the Shape abstract class.They each have a member of type Renderer to hold a reference to the renderer implementation.




class Circle : public Shape {
public:
    Circle(Renderer& renderer) : renderer(renderer) {}
 
    void draw() override {
        std::cout << "Drawing a circle ";
        renderer.render();
    }
 
private:
    Renderer& renderer;
};
 
class Square : public Shape {
public:
    Square(Renderer& renderer) : renderer(renderer) {}
 
    void draw() override {
        std::cout << "Drawing a square ";
        renderer.render();
    }
 
private:
    Renderer& renderer;
};

Main Function:

In the main() function, instances of VectorRenderer and RasterRenderer are created.Instances of Circle and Square are also created, each associated with a specific renderer.Calling draw() on Shapes circle.draw() is called, which internally calls the VectorRenderer to render the circle, and square.draw() is called, which internally calls the RasterRenderer to render the square.




int main() {
    VectorRenderer vectorRenderer;
    RasterRenderer rasterRenderer;
 
    Circle circle(vectorRenderer);
    Square square(rasterRenderer);
 
    circle.draw();  // Output: Drawing a circle Rendering as a vector
    square.draw();  // Output: Drawing a square Rendering as a raster
 
    return 0;
}

Below is the complete combined code of the above example:




#include <iostream>
 
// Abstraction: Shape
class Shape {
public:
    virtual void draw() = 0;
};
 
// Implementations: Renderer (VectorRenderer and
// RasterRenderer)
class Renderer {
public:
    virtual void render() = 0;
};
 
class VectorRenderer : public Renderer {
public:
    void render() override
    {
        std::cout << "Rendering as a vector\n";
    }
};
 
class RasterRenderer : public Renderer {
public:
    void render() override
    {
        std::cout << "Rendering as a raster\n";
    }
};
 
// Concrete Abstractions: Circle and Square
class Circle : public Shape {
public:
    Circle(Renderer& renderer)
        : renderer(renderer)
    {
    }
 
    void draw() override
    {
        std::cout << "Drawing a circle ";
        renderer.render();
    }
 
private:
    Renderer& renderer;
};
 
class Square : public Shape {
public:
    Square(Renderer& renderer)
        : renderer(renderer)
    {
    }
 
    void draw() override
    {
        std::cout << "Drawing a square ";
        renderer.render();
    }
 
private:
    Renderer& renderer;
};
 
int main()
{
    VectorRenderer vectorRenderer;
    RasterRenderer rasterRenderer;
 
    Circle circle(vectorRenderer);
    Square square(rasterRenderer);
 
    circle.draw(); // Output: Drawing a circle Rendering as
                   // a vector
    square.draw(); // Output: Drawing a square Rendering as
                   // a raster
 
    return 0;
}

Output
Drawing a circle Rendering as a vector
Drawing a square Rendering as a raster

Key components of Bridge Patterns in C++:

Working and explanation of Example by using Key Component:

In the above example:

Diagrammatic Representation of the Example

Diagrammatical Representation of the Example

Advantages of the Bridge Design Pattern in C++ Design Patterns

Disadvantages of the Bridge Design Patterns in C++ Design Patterns

Conclusion

So Basically, the Bridge Pattern allows us to create a hierarchy of abstractions and implementations. we can change or extend the implementation independently of the abstraction, and the client code can work with different implementations without needing to change its code. This makes it easier to add new features, support multiple platforms, or maintain and extend your software.


Article Tags :