Bridge Pattern in Python: Separate Abstraction from Implementation

Implement the Bridge design pattern in Python so that an abstraction (remote control) can operate on different device implementations independently.

Medium Python 3.9+ Aug 9, 2026 OOP & classes 15 views 0 copies

Python code

99 lines
Python 3.9+
class RemoteControl:
    """Abstraction: controls a device without knowing implementation details."""
    def __init__(self, device):
        self.device = device

    def toggle_power(self):
        if self.device.is_enabled():
            self.device.disable()
            return "Power off"
        else:
            self.device.enable()
            return "Power on"

    def volume_up(self):
        volume = self.device.get_volume()
        self.device.set_volume(volume + 10)
        return f"Volume: {self.device.get_volume()}"


class AdvancedRemoteControl(RemoteControl):
    """Refined abstraction: adds mute functionality."""
    def mute(self):
        self.device.set_volume(0)
        return "Muted"


class Device:
    """Implementation interface."""
    def enable(self):
        pass

    def disable(self):
        pass

    def is_enabled(self):
        pass

    def get_volume(self):
        pass

    def set_volume(self, percent):
        pass


class TV(Device):
    """Concrete implementation for TV."""
    def __init__(self):
        self._on = False
        self._volume = 30

    def enable(self):
        self._on = True

    def disable(self):
        self._on = False

    def is_enabled(self):
        return self._on

    def get_volume(self):
        return self._volume

    def set_volume(self, percent):
        self._volume = max(0, min(100, percent))


class Radio(Device):
    """Concrete implementation for Radio."""
    def __init__(self):
        self._on = False
        self._volume = 20

    def enable(self):
        self._on = True

    def disable(self):
        self._on = False

    def is_enabled(self):
        return self._on

    def get_volume(self):
        return self._volume

    def set_volume(self, percent):
        self._volume = max(0, min(100, percent))


if __name__ == "__main__":
    tv = TV()
    remote = AdvancedRemoteControl(tv)
    print(remote.toggle_power())
    print(remote.volume_up())
    print(remote.mute())

    radio = Radio()
    basic_remote = RemoteControl(radio)
    print(basic_remote.toggle_power())
    print(basic_remote.volume_up())

Output

stdout
Power on
Volume: 40
Muted
Power on
Volume: 30

How it works

The Bridge pattern decouples an abstraction from its implementation so they can evolve independently. Here, RemoteControl defines the high-level operations and holds a reference to a Device interface. Concrete devices (TV, Radio) implement the interface, allowing any remote to control any device. This composition over inheritance keeps changes to one side from rippling to the other.

Common mistakes

  • Forgetting to pass a device instance when creating a remote control (TypeError or None attribute access).
  • Implementing device logic directly inside the remote class, which defeats the purpose of the bridge.
  • Not using an interface class, leading to tight coupling between remote and concrete devices.

Variations

  1. Use `Protocol` from typing to define the device interface (structural subtyping).
  2. Add more refined abstractions like `AdvancedRemoteControl` with additional methods while keeping devices unchanged.

Real-world use cases

  • GUI frameworks where the same window abstraction drives different widgets on Windows/macOS.
  • Database abstraction layers that let an app switch from MySQL to PostgreSQL without changing business logic.
  • Cross-platform UI controllers that operate devices like TVs and projectors via the same remote interface.

Sponsored

Run this sample

Open the browser IDE to tweak the example and see results without installing anything.

Open editor

More from OOP & classes

Related tutorials and quizzes for this topic.