Design Pattern: Bridge Pattern in Python

Bridge pattern is used to separate/decouple the abstraction from the implementation, so that we can change those separately. The bridge pattern works as the communication for those two separate parts.

NOTES

In this article, we discuss the implementation of the Bridge Pattern in Python.

See the Bridge in other languages in the “Other Code Implementations” section. Or, use the link below to check the details of the Bridge Pattern-

Implementation

Create a component interface using Python Protocol or Abstract Base Class(ABC).
Create some component and implement the interface
Create an abstract class for the main modules, using Abstract Base Class(ABC).
In the “__init__” method of the module abstract class, accept an instance of the complenent.
Create the moduel classes, and inherith from the module abstract class.
In the module clases use the instance of component, in different method implementations, as per requirement.

Here is a simple example of Bridge pattern implemenation in Python-

from typing import Protocol
from abc import ABC, abstractmethod


# Plugin interface using Protocol
class PluginI(Protocol):
    def plugin_operation_1(self) -> None: 
        ...


# First plugin
class Plugin1:
    def plugin_operation_1(self) -> None:
        print("Plugin 1: operation 1")


# Second plugin
class Plugin2:
    def plugin_operation_1(self) -> None:
        print("Plugin 2: operation 1")


# Module interface using Protocol
class Module(ABC):
    def __init__(self, plugin: PluginI) -> None:
        self.plugin = plugin

    @abstractmethod
    def module_operation_1(self) -> None:
        pass


# First module
class Module1(Module):
    def __init__(self, plugin: PluginI) -> None:
        self.plugin = plugin

    def module_operation_1(self) -> None:
        print("Module 1: operation 1")
        self.plugin.plugin_operation_1()


# Second module
class Module2(Module):
    def __init__(self, plugin: PluginI) -> None:
        self.plugin = plugin

    def module_operation_1(self) -> None:
        print("Module 2: operation 1")
        self.plugin.plugin_operation_1()


# Demo Usage
def main():
    module1 = Module1(Plugin2())
    module1.module_operation_1()


if __name__ == "__main__":
    main()
Python

Here is the output of the above implementation-

Module 1: operation 1
Plugin 2: operation 1
Plaintext

Examples

Check the following examples of Bridge pattern implementation-

Example #1: UI Elements

In this exmple we have main modules for different UI elements, like- Button, Table, Input. And we have compnents for different colors.

Let’s see how can we separat the modules from the colors, and use the colors for the component, when we need it.

Color Interface

Create “Color” class, and inherit from “ABC“. We can also use Python “Protocol” if we prefer.
Declare an abstract method “set_color“.
from abc import ABC, abstractmethod


# Color interface
class Color(ABC):
    @abstractmethod
    def set_color(self) -> None:
        pass
Python

Red [Color Schema]

Create class “Red” and inherit from “Color” class(interface).
In the “set_color” method definition add the steps for implementing/setting red color for an element.
# Red color class
class Red(Color):
    def set_color(self) -> None:
        print("Setting proper color for Red color schema")
Python

Green [Color Schema]

Create class “Green” and inherit from “Color” class(interface).
In the “set_color” method definition add the steps for implementing/setting green color for an element.
# Green color class
class Green(Color):
    def set_color(self) -> None:
        print("Setting proper color for Green color schema")
Python

Blue [Color Schema]

Create class “Blue” and inherit from “Color” class(interface).
In the “set_color” method definition add the steps for implementing/setting blue color for an element.
# Blue color class
class Blue(Color):
    def set_color(self) -> None:
        print("Setting proper color for Blue color schema")
Python

UI Element Interface

Create abstract class “UIElement“.
In the “__init__” method accept an instance of type “Color” and save the instance in an attribute named “color“.
Declare an abstract method named “print_element“.
# UIElement abstract class
class UIElement(ABC):
    def __init__(self, color: Color) -> None:
        self.color = color

    @abstractmethod
    def print_element(self) -> None:
        pass
Python

Button [UI Element]

Create “Button” class and inherit from “UIElement“.
In the “print_element” method implementation use the method from “color” instance.
# Button class
class Button(UIElement):
    def print_element(self) -> None:
        self.color.set_color()
        print("Printing Button")
Python

Input [UI Element]

Create “Input” class and inherit from “UIElement“.
In the “print_element” method implementation use the method from “color” instance.
# Input class
class Input(UIElement):
    def print_element(self) -> None:
        self.color.set_color()
        print("Printing Input")
Python

Table [UI Element]

Create “Table” class and inherit from “UIElement“.
In the “print_element” method implementation use the method from “color” instance.
# Table class
class Table(UIElement):
    def print_element(self) -> None:
        self.color.set_color()
        print("Printing Table")
Python

Demo

# Demo Usage
def main():
    table = Table(Red())
    table.print_element()

    input_element = Input(Green())
    input_element.print_element()

    button = Button(Blue())
    button.print_element()

    button2 = Button(Red())
    button2.print_element()


if __name__ == "__main__":
    main()
Python

Output

Output will be as follows-

Setting proper color for Red color schema
Printing Table


Setting proper color for Green color schema
Printing Input


Setting proper color for Blue color schema
Printing Button


Setting proper color for Red color schema
Printing Button
Plaintext

Example #2: Transport Seat

In this example we have different type of seats and different type of transports. Let’s see how can we dynamically use the same seat compnent classes for different type of transports.

Seat Interface

Create class “Seat” and use “Protocol” for this class.
Declare method “select_seat“.
from typing import Protocol


# Seat interface using Protocol
class Seat(Protocol):
    def select_seat(self) -> None:
        pass
Python

Business Class Seat [Seat Type]

Create class “BusinessClassSeat“.
Implement protocol “Seat“.
In the method definition “select_seat” implement all steps/instructions for selecting a seat of business class.
# BusinessClassSeat class
class BusinessClassSeat:
    def select_seat(self) -> None:
        print("Select a Business class seat")
Python

Economy Class Seat [Seat Type]

Create class “EconomyClassSeat“.
Implement protocol “Seat” and add definition for method “select_seat” as part of protocol implementation.
# EconomyClassSeat class
class EconomyClassSeat:
    def select_seat(self) -> None:
        print("Select an Economy class seat")
Python

Transport Interface

Create class “Transport“.
Inheright from “ABC” to make it an abstract class.
In the “__init__” method definition accept an object of type “Seat“.
Declare an abstract method “select_transport“.
from abc import ABC, abstractmethod

# Transport abstract class
class Transport(ABC):
    def __init__(self, seat: Seat) -> None:
        self.seat = seat

    @abstractmethod
    def select_transport(self) -> None:
        pass
Python

Plane [Transport]

Creatre class “Plane“.
Inherit from “Transport“.
In the “select_transport” method definition, add all steps for selecting the plane as transport, and also use the method from “Seat” instance.
# Plane class
class Plane(Transport):
    def select_transport(self) -> None:
        print("Plane selected for transport")
        self.seat.select_seat()
Python

Train [Transport]

Creatre class “Train“.
Inherit from “Transport“.
In the “select_transport” method definition, add all steps for selecting the train as transport, and also use the method from “Seat” instance.
# Train class
class Train(Transport):
    def select_transport(self) -> None:
        print("Train selected for transport")
        self.seat.select_seat()
Python

Demo

# Demo usage
def main():
    plane = Plane(BusinessClassSeat())
    plane.select_transport()

    plane2 = Plane(EconomyClassSeat())
    plane2.select_transport()

    train = Train(EconomyClassSeat())
    train.select_transport()


if __name__ == "__main__":
    main()
Python

Output

We will get the following output.

Plane selected for transport
Select an Business class seat

Plane selected for transport
Select an Economy class seat

Train selected for transport
Select an Economy class seat
Plaintext

Source Code

Use the following link to get the source code:

Other Code Implementations

Use the following links to check the implementation of the bridge pattern in other programming languages.

Leave a Comment


The reCAPTCHA verification period has expired. Please reload the page.