terminal

codeando_simple

terminal

menu

terminal

search_module

guest@codeandosimple: ~/system/search $ grep -r "" .

Press [ENTER] to execute search

Status

Engine: Ready

Database: Online

Index: V2.1.0_LATEST

Software Design / Bridge
guest@codeandosimple: ~/blog/design-patterns $ cat bridge.md

Bridge Pattern_

// "Simplicity is the soul of efficiency" - Austin Freeman

call_split What does it consist of?

The Bridge is a structural pattern that divides a large class or a closely related group of classes into two separate hierarchies: abstraction and implementation, which can be developed independently.

This pattern is especially useful when we have a class with multiple dimensions of variation. Instead of creating a subclass for every possible combination (which leads to an exponential explosion of classes), we separate those dimensions.

Practical Example: Remote Controls and Devices

Imagine we have a RemoteControl class and a Device class. A remote control can be basic or advanced, and a device can be a TV or a Radio. If we mix everything, we would have BasicTVRemote, AdvancedTVRemote, BasicRadioRemote, and so on.

Bridge Example

# The logic behind it

The Bridge pattern solves this by extracting one of the dimensions into a separate hierarchy. The RemoteControl (Abstraction) contains a reference to an object of type Device (Implementation).

The remote delegates the actual work (like turning on or changing the volume) to the linked device object. This allows us to change the devices and the remotes completely independently from one another.

# Structure

Bridge UML Diagram

# Implementation

Bridge.php
<?php

// 1. Implementation
interface Device {
    public function isEnabled(): bool;
    public function enable(): void;
    public function disable(): void;
    public function getVolume(): int;
    public function setVolume(int $percent): void;
}

// 2. Concrete Implementations
class TV implements Device {
    private bool $on = false;
    private int $volume = 30;

    public function isEnabled(): bool { return $this->on; }
    public function enable(): void { $this->on = true; }
    public function disable(): void { $this->on = false; }
    public function getVolume(): int { return $this->volume; }
    public function setVolume(int $percent): void { $this->volume = $percent; }
}

class Radio implements Device {
    private bool $on = false;
    private int $volume = 10;

    public function isEnabled(): bool { return $this->on; }
    public function enable(): void { $this->on = true; }
    public function disable(): void { $this->on = false; }
    public function getVolume(): int { return $this->volume; }
    public function setVolume(int $percent): void { $this->volume = $percent; }
}

// 3. Abstraction
class RemoteControl {
    protected Device $device;

    public function __construct(Device $device) {
        $this->device = $device;
    }

    public function togglePower(): void {
        echo "Remote: Power toggle\n";
        if ($this->device->isEnabled()) {
            $this->device->disable();
        } else {
            $this->device->enable();
        }
    }

    public function volumeDown(): void {
        echo "Remote: Volume down\n";
        $this->device->setVolume($this->device->getVolume() - 10);
    }
}

// 4. Refined Abstraction
class AdvancedRemoteControl extends RemoteControl {
    public function mute(): void {
        echo "Remote: Mute\n";
        $this->device->setVolume(0);
    }
}

// Usage
$tv = new TV();
$remote = new RemoteControl($tv);
$remote->togglePower();

$radio = new Radio();
$advancedRemote = new AdvancedRemoteControl($radio);
$advancedRemote->togglePower();
$advancedRemote->mute();

# Mapping Participants

  • Device (Implementation): Declares the interface common to all concrete implementations.

  • TV, Radio (ConcreteImplementations): The concrete components that implement the Device interface.

  • RemoteControl (Abstraction): High-level control logic. It delegates work to the concrete implementation.

  • AdvancedRemoteControl (RefinedAbstraction): Extends the control logic of the basic abstraction.

# Conclusions

The Bridge pattern prevents class explosion when extending logic in multiple dimensions independently. In our example, we can add new devices (like a Projector) without modifying existing remotes, and we can add new remotes (like a SmartAppRemote) without changing existing devices.

# Related Patterns

Adapter

Bridge is typically designed upfront so that abstractions and implementations can vary independently. Adapter is applied after the fact to make unrelated classes work together.

State / Strategy

Bridge, State, Strategy (and to some extent Adapter) have very similar structures as all are based on composition. However, they solve different problems.

Abstract Factory

Abstract Factory can be paired with Bridge. This is useful when some abstractions defined by Bridge can only work with specific implementations.