×

Bridge Design Pattern with Python

Bridge Design Patterns Python Feature

The Bridge design pattern suggests connecting various components present in an application through abstraction.

The main motivation behind Bridge pattern is, Bridge Design Pattern prevents a “Cartesian Product” complexity explosion.

A Bridge suggests implementation that decouples an interface(hierarchy) from an implementation(hierarchy). These are the formal definitions, which complicate the scenario. Let’s understand everything with an example.

Example:

Consider there is a shape abstract class, for various shapes(i.e. square, circle, etc):

class shape:
    def no_of_sides(self, sides):
        self.sides = sides
    @abstractmethod
    def Find_area(self):
        pass

Expanding Shape class in – Square and Circle concrete classes:

class Square(shape):
    def __init__(self, width, sides):
        self.width = width
        super().no_of_sides(sides)
    
    def Find_area(self):
        return self.width ** 2

class Circle(shape):
    def __init__(self, radius, sides):
        self.width = radius
        super().no_of_sides(0)
    
    def Find_area(self):
        return 3.14*self.radius**2

Now, if we want to expand the shapes hierarchy in color, that is, to have the Red and Blue shapes. We have to create 4 combinations of subclasses, like BlueCircle and RedSquare.

class RedSquare(shape):
    pass
class BlueSquare(shape):
    pass
class RedCircle(shape):
    pass
class RedCircle(shape):
    pass

What if we add a Triangle shape? The number of combinations possible will be 8 now. The increasing number of combinations is the complexity explosion. Here number combinations are increasing in powers of 2.

The problem can be resolved by decoupling the interface, which is here Shape and its implementations, that are RedSquare, BlueCircle etc. Decoupling simply means creating a new interface for the implementations themselves. Interface for color.

class Color:
    def fill_color(self):
        pass

Now, subclasses for Color:

class RedColor(Color):
    def __init__(self):
        self.fill_color()
    def fill_color(self):
        self._color = 'Red'

With separate implementation for both hierarchies adding new color classes, won’t need to alter the shape classes, and vice versa. 

Full implementation will be like this:

from abc import abstractmethod
"""Abstract class for Shapes"""
class shape:
    def no_of_sides(self, sides):
        self.sides = sides
    def set_color(self, color):
        self.color = color._color   
    @abstractmethod
    def Find_area(self):
        pass    
    
class Square(shape):
    def __init__(self, width, sides, color):
        self.width = width
        super().no_of_sides(sides)
        super().set_color(color)

    def Find_area(self):
        return self.width ** 2
        
    """Method to get information of the class."""
    def __str__(self):
        return f'Shape: {type(self).__name__}, Side: {self.sides}, Colour: {self.color}, Area: {self.Find_area()}'

class Circle(shape):
    def __init__(self, radius, sides, color):
        self.radius = radius
        super().no_of_sides(0)
        super().set_color(color)    

    def Find_area(self):
        return 3.14*self.radius**2
    
    def __str__(self):
        return f'Shape: {type(self).__name__}, Side: {self.sides}, Colour: {self.color}, Area: {self.Find_area()}'
        
"""Interface for implementation"""
class Color:
    def fill_color(self):
        pass
"""Subclass for implementation interface."""
class RedColor(Color):
    def __init__(self):
        self.fill_color()
    def fill_color(self):
        self._color = 'Red'

class BlueColor(Color):
    def __init__(self):
        self.fill_color()
    def fill_color(self):
        self._color = 'Blue'

#Driver Code
objS = Square(4, 4, RedColor())
objC = Circle(2, 0, BlueColor())
print(objS, objC, sep="\n")

Output:

Shape: Square, Side: 4, Colour: Red, Area: 16
Shape: Circle, Side: 0, Colour: Blue, Area: 12.56

Bridge Pattern can help in:

  • Where class contains a number of functionalities and needs to be divided into individual classes with specific funtionalities.
  • Implementation of entities needs to be changed during the execution of a program.

Pros and Cons of Bridge Pattern

Pros

  • Allows building platform-independent programs.
  • Hides unnecessary or dangerous implementation details from the client code.

Cons

  • Complicates the program code due to the introduction of additional classes.