Overview of the Bridge Pattern The Bridge pattern is a structural design pattern that separates a large class or a set of closely related classes into two separate hierarchies: **abstraction** and **implementation**. This matters because it allows both hierarchies to develop independently. Imagine a streaming application where you have services like YouTube or Twitch and hardware like webcams or DSLR cameras. Without a bridge, you might end up with a combinatorial explosion of classes (e.g., `YouTubeWebcam`, `YouTubeDSLR`, `TwitchWebcam`). The Bridge pattern fixes this by making the service hold a reference to the device, decoupling the two. Prerequisites To follow this guide, you should understand Python basics, specifically: - Class inheritance and composition. - The concept of interfaces (how one object interacts with another). - Basic familiarity with Type Hinting and decorators. Key Libraries & Tools - `abc`: The Abstract Base Classes module for defining formal interfaces. - `typing`: Specifically `Protocol` for structural subtyping and `Callable` for functional approaches. - `dataclasses`: Used to reduce boilerplate when creating data-holding classes. - `mermaid`: A text-based diagramming tool used for visualizing UML relationships. Code Walkthrough: From Protocols to ABCs Initially, we can define the relationship using a `Protocol`. This allows for duck-typing where the service doesn't care about the device's class hierarchy, only that it has a `get_buffer_data` method. ```python from typing import Protocol class StreamingDevice(Protocol): def get_buffer_data(self) -> str: ... ``` However, Python allows us to be even more functional. Since a device just "gets data," we can replace the entire device hierarchy with a `Callable` type alias. This removes the need for extra classes entirely. ```python from typing import Callable BufferData = str Buffer = Callable[[], BufferData] def get_webcam_data() -> BufferData: return "Webcam data stream" ``` To add more power, we move back to an Abstract Base Class (ABC). This allows us to implement shared logic, such as managing a list of multiple devices, directly in the parent class. ```python from abc import ABC, abstractmethod from dataclasses import dataclass, field @dataclass class StreamingService(ABC): devices: list[Buffer] = field(default_factory=list) def add_device(self, device: Buffer): self.devices.append(device) @abstractmethod def start_stream(self): ... ``` Syntax Notes - **First-Class Functions**: We pass functions like `get_webcam_data` as arguments without calling them (omitting the parentheses). This treats logic as data. - **Default Factory**: In dataclasses, we use `field(default_factory=list)` to avoid the "mutable default argument" trap. Practical Examples - **Cross-Platform UI**: Separating a UI component (Button) from the OS implementation (Windows vs. macOS). - **Database Drivers**: A generic `Database` abstraction using specific `PostgreSQL` or `MongoDB` implementations. Tips & Gotchas Avoid using `Protocol` when you need to share implementation logic; that's where `ABC` shines. If your implementation hierarchy is just a single method, skip the class and use a function to keep your codebase lean.
Type Hinting
Software Development
Feb 2022 • 1 videos
High activity month for Type Hinting. ArjanCodes among the most active voices, with 1 videos across 1 sources.
Feb 2022
- Feb 18, 2022