Bridge (Мост)

Паттерн Bridge (Мост) разделяет абстракцию и реализацию, позволяя им развиваться независимо друг от друга. Он особенно полезен, когда нужно избежать жёсткой зависимости между высокоуровневыми и низкоуровневыми компонентами.

Когда применять Bridge

  • Когда нужно разделить большую систему на независимые уровни (например, UI и графический движок).
  • Когда требуется менять реализацию объектов без изменения их интерфейсов.
  • Когда классы растут в обе стороны — по типам и по вариантам реализации.

PlantUML-диаграмма

UML диаграмма Bridge

// Интерфейс реализации
public interface IDevice
{
    bool IsEnabled { get; }
    void Enable();
    void Disable();
    int GetVolume();
    void SetVolume(int percent);
}

// Конкретная реализация — Радио
public class Radio : IDevice
{
    private int _volume = 30;
    public bool IsEnabled { get; private set; }

    public void Enable() => IsEnabled = true;
    public void Disable() => IsEnabled = false;
    public int GetVolume() => _volume;
    public void SetVolume(int percent) => _volume = percent;
}

// Конкретная реализация — Телевизор
public class Tv : IDevice
{
    private int _volume = 50;
    public bool IsEnabled { get; private set; }

    public void Enable() => IsEnabled = true;
    public void Disable() => IsEnabled = false;
    public int GetVolume() => _volume;
    public void SetVolume(int percent) => _volume = percent;
}

// Абстракция — пульт управления
public class Remote
{
    protected IDevice _device;

    public Remote(IDevice device)
    {
        _device = device;
    }

    public void TogglePower()
    {
        if (_device.IsEnabled)
            _device.Disable();
        else
            _device.Enable();
    }

    public void VolumeDown()
    {
        _device.SetVolume(_device.GetVolume() - 10);
    }

    public void VolumeUp()
    {
        _device.SetVolume(_device.GetVolume() + 10);
    }
}

// Расширенная абстракция — умный пульт
public class AdvancedRemote : Remote
{
    public AdvancedRemote(IDevice device) : base(device) { }

    public void Mute()
    {
        _device.SetVolume(0);
    }
}

// Клиентский код
class Program
{
    static void Main()
    {
        IDevice tv = new Tv();
        Remote remote = new Remote(tv);
        remote.TogglePower();

        IDevice radio = new Radio();
        AdvancedRemote advanced = new AdvancedRemote(radio);
        advanced.TogglePower();
        advanced.Mute();

        Console.WriteLine($"TV включен: {tv.IsEnabled}, громкость: {tv.GetVolume()}");
        Console.WriteLine($"Radio включено: {radio.IsEnabled}, громкость: {radio.GetVolume()}");
    }
}
// Интерфейс реализации
type Device interface {
	IsEnabled() bool
	Enable()
	Disable()
	Volume() int
	SetVolume(percent int)
}

type Radio struct {
	enabled bool
	volume  int
}

func NewRadio() *Radio { return &Radio{volume: 30} }

func (r *Radio) IsEnabled() bool         { return r.enabled }
func (r *Radio) Enable()                 { r.enabled = true }
func (r *Radio) Disable()                { r.enabled = false }
func (r *Radio) Volume() int             { return r.volume }
func (r *Radio) SetVolume(percent int)   { r.volume = percent }

type Tv struct {
	enabled bool
	volume  int
}

func NewTv() *Tv { return &Tv{volume: 50} }

func (t *Tv) IsEnabled() bool       { return t.enabled }
func (t *Tv) Enable()               { t.enabled = true }
func (t *Tv) Disable()              { t.enabled = false }
func (t *Tv) Volume() int           { return t.volume }
func (t *Tv) SetVolume(percent int) { t.volume = percent }

// Абстракция — пульт управления
type Remote struct {
	device Device
}

func (r Remote) TogglePower() {
	if r.device.IsEnabled() {
		r.device.Disable()
	} else {
		r.device.Enable()
	}
}

func (r Remote) VolumeDown() { r.device.SetVolume(r.device.Volume() - 10) }
func (r Remote) VolumeUp()   { r.device.SetVolume(r.device.Volume() + 10) }

// Расширенная абстракция: встраивание вместо наследования
type AdvancedRemote struct {
	Remote
}

func (r AdvancedRemote) Mute() { r.device.SetVolume(0) }

func main() {
	tv := NewTv()
	Remote{device: tv}.TogglePower()

	radio := NewRadio()
	advanced := AdvancedRemote{Remote{device: radio}}
	advanced.TogglePower()
	advanced.Mute()

	fmt.Printf("TV включен: %t, громкость: %d\n", tv.IsEnabled(), tv.Volume())
	fmt.Printf("Radio включено: %t, громкость: %d\n", radio.IsEnabled(), radio.Volume())
}
from typing import Protocol


class Device(Protocol):
    def is_enabled(self) -> bool: ...
    def enable(self) -> None: ...
    def disable(self) -> None: ...
    def get_volume(self) -> int: ...
    def set_volume(self, percent: int) -> None: ...


class Radio:
    def __init__(self) -> None:
        self._enabled = False
        self._volume = 30

    def is_enabled(self) -> bool:
        return self._enabled

    def enable(self) -> None:
        self._enabled = True

    def disable(self) -> None:
        self._enabled = False

    def get_volume(self) -> int:
        return self._volume

    def set_volume(self, percent: int) -> None:
        self._volume = percent


class Tv:
    def __init__(self) -> None:
        self._enabled = False
        self._volume = 50

    def is_enabled(self) -> bool:
        return self._enabled

    def enable(self) -> None:
        self._enabled = True

    def disable(self) -> None:
        self._enabled = False

    def get_volume(self) -> int:
        return self._volume

    def set_volume(self, percent: int) -> None:
        self._volume = percent


class Remote:
    def __init__(self, device: Device) -> None:
        self._device = device

    def toggle_power(self) -> None:
        if self._device.is_enabled():
            self._device.disable()
        else:
            self._device.enable()

    def volume_down(self) -> None:
        self._device.set_volume(self._device.get_volume() - 10)

    def volume_up(self) -> None:
        self._device.set_volume(self._device.get_volume() + 10)


class AdvancedRemote(Remote):
    def mute(self) -> None:
        self._device.set_volume(0)


tv = Tv()
Remote(tv).toggle_power()

radio = Radio()
advanced = AdvancedRemote(radio)
advanced.toggle_power()
advanced.mute()

print(f"TV включен: {tv.is_enabled()}, громкость: {tv.get_volume()}")
print(f"Radio включено: {radio.is_enabled()}, громкость: {radio.get_volume()}")
interface Device {
    isEnabled(): boolean;
    enable(): void;
    disable(): void;
    getVolume(): number;
    setVolume(percent: number): void;
}

class Radio implements Device {
    private enabled = false;
    private volume = 30;

    isEnabled(): boolean {
        return this.enabled;
    }

    enable(): void {
        this.enabled = true;
    }

    disable(): void {
        this.enabled = false;
    }

    getVolume(): number {
        return this.volume;
    }

    setVolume(percent: number): void {
        this.volume = percent;
    }
}

class Tv implements Device {
    private enabled = false;
    private volume = 50;

    isEnabled(): boolean {
        return this.enabled;
    }

    enable(): void {
        this.enabled = true;
    }

    disable(): void {
        this.enabled = false;
    }

    getVolume(): number {
        return this.volume;
    }

    setVolume(percent: number): void {
        this.volume = percent;
    }
}

class Remote {
    constructor(protected device: Device) {}

    togglePower(): void {
        if (this.device.isEnabled()) this.device.disable();
        else this.device.enable();
    }

    volumeDown(): void {
        this.device.setVolume(this.device.getVolume() - 10);
    }

    volumeUp(): void {
        this.device.setVolume(this.device.getVolume() + 10);
    }
}

class AdvancedRemote extends Remote {
    mute(): void {
        this.device.setVolume(0);
    }
}

const tv = new Tv();
new Remote(tv).togglePower();

const radio = new Radio();
const advanced = new AdvancedRemote(radio);
advanced.togglePower();
advanced.mute();

console.log(`TV включен: ${tv.isEnabled()}, громкость: ${tv.getVolume()}`);
console.log(`Radio включено: ${radio.isEnabled()}, громкость: ${radio.getVolume()}`);
interface Device {
    boolean isEnabled();
    void enable();
    void disable();
    int getVolume();
    void setVolume(int percent);
}

class Radio implements Device {
    private boolean enabled;
    private int volume = 30;

    public boolean isEnabled() {
        return enabled;
    }

    public void enable() {
        enabled = true;
    }

    public void disable() {
        enabled = false;
    }

    public int getVolume() {
        return volume;
    }

    public void setVolume(int percent) {
        volume = percent;
    }
}

class Tv implements Device {
    private boolean enabled;
    private int volume = 50;

    public boolean isEnabled() {
        return enabled;
    }

    public void enable() {
        enabled = true;
    }

    public void disable() {
        enabled = false;
    }

    public int getVolume() {
        return volume;
    }

    public void setVolume(int percent) {
        volume = percent;
    }
}

class Remote {
    protected final Device device;

    Remote(Device device) {
        this.device = device;
    }

    void togglePower() {
        if (device.isEnabled()) device.disable();
        else device.enable();
    }

    void volumeDown() {
        device.setVolume(device.getVolume() - 10);
    }

    void volumeUp() {
        device.setVolume(device.getVolume() + 10);
    }
}

class AdvancedRemote extends Remote {
    AdvancedRemote(Device device) {
        super(device);
    }

    void mute() {
        device.setVolume(0);
    }
}

public class Program {
    public static void main(String[] args) {
        Device tv = new Tv();
        new Remote(tv).togglePower();

        Device radio = new Radio();
        AdvancedRemote advanced = new AdvancedRemote(radio);
        advanced.togglePower();
        advanced.mute();

        System.out.printf("TV включен: %b, громкость: %d%n", tv.isEnabled(), tv.getVolume());
        System.out.printf("Radio включено: %b, громкость: %d%n", radio.isEnabled(), radio.getVolume());
    }
}
interface Device {
    var isEnabled: Boolean
    var volume: Int
}

class Radio : Device {
    override var isEnabled = false
    override var volume = 30
}

class Tv : Device {
    override var isEnabled = false
    override var volume = 50
}

open class Remote(protected val device: Device) {
    fun togglePower() {
        device.isEnabled = !device.isEnabled
    }

    fun volumeDown() {
        device.volume -= 10
    }

    fun volumeUp() {
        device.volume += 10
    }
}

class AdvancedRemote(device: Device) : Remote(device) {
    fun mute() {
        device.volume = 0
    }
}

fun main() {
    val tv = Tv()
    Remote(tv).togglePower()

    val radio = Radio()
    val advanced = AdvancedRemote(radio)
    advanced.togglePower()
    advanced.mute()

    println("TV включен: ${tv.isEnabled}, громкость: ${tv.volume}")
    println("Radio включено: ${radio.isEnabled}, громкость: ${radio.volume}")
}

Плюсы и минусы

Плюсы Минусы
Позволяет изменять реализацию и абстракцию независимо Усложняет структуру из-за необходимости введения дополнительных классов
Уменьшает количество подклассов при комбинации различных реализаций Может быть избыточным при простых иерархиях
Повышает гибкость системы и следование принципам SOLID Требует внимательного проектирования интерфейсов

Заключение

Bridge помогает отделить логику управления (абстракцию) от конкретных реализаций, делая код масштабируемым и удобным для расширения. Это отличный выбор для систем, где требуется поддерживать множество вариантов поведения и платформ.