Pular para o conteúdo
GoF Padrões de Projeto Estruturais
Estrutural escopo de objeto
GoF, p. 151 também chamado de Handle/Body

Ponte

Bridge

Separa abstração de implementação para que as duas variem sem multiplicar classes.

Complexidade alta Frequência de uso rara
Intençãocomo o livro define

Desacoplar uma abstração da sua implementação, de modo que as duas possam variar independentemente.

Analogiauma imagem do mundo real

Controle remoto e aparelho

Existem vários tipos de controle remoto (básico, com voz, app no celular) e vários aparelhos (TV, rádio, ar-condicionado). Se cada combinação virasse uma classe, seriam 3 × 3 = 9 classes — e 4 × 4 = 16 quando você adicionasse mais um de cada. A ponte é o protocolo: todo controle fala “ligar / desligar / volume”, e cada aparelho implementa isso do seu jeito. Agora são 3 + 3 classes, e crescem somando, não multiplicando.

O problema

Duas dimensões de variação independentes na mesma hierarquia geram explosão combinatória. Forma × Cor: CírculoVermelho, CírculoAzul, QuadradoVermelho, QuadradoAzul… Cada nova cor multiplica o número de classes.

A solução

Extraia uma das dimensões para uma hierarquia separada (a Implementação) e faça a hierarquia original (a Abstração) referenciá-la por composição. A “ponte” é essa referência.

Sintomascomo reconhecer no seu código
  • Nomes de classe com duas dimensões coladas: RelatorioPDFMensal, RelatorioExcelMensal
  • Um if (plataforma) dentro de cada método de uma hierarquia.

Estrutura

🌉 a ponte«abstrata»Controle# aparelho+ ligar()+ volume(±)ControleAvancado+ mudo()«interface»Aparelho+ ligar()+ setVolume(v)TVRadio
Fig. 7 — Bridge herda / implementa cria usa / contém
Ver este diagrama sendo desenhado, traço a traço
Participantes
Abstraction
Interface de alto nível; mantém uma referência a Implementor e delega o trabalho real.
RefinedAbstraction
Variantes da lógica de alto nível.
Implementor
Interface das operações primitivas de baixo nível.
ConcreteImplementor
Implementações específicas de plataforma/tecnologia.

Implementação

Listagem 7 Notificações: canal × urgência variando de forma independente
// ── Implementação: COMO a mensagem sai (o canal) ──────
class Canal { enviar(destino, texto) { throw new Error('abstrato'); } }

class CanalEmail    extends Canal { enviar(d, t) { return `✉️  e-mail  → ${d}: ${t}`; } }
class CanalSMS      extends Canal { enviar(d, t) { return `📱 sms     → ${d}: ${t.slice(0, 140)}`; } }
class CanalSlack    extends Canal { enviar(d, t) { return `💬 slack   → #${d}: ${t}`; } }

// ── Abstração: O QUE é notificado (a política) ────────
class Notificacao {
  constructor(canal) { this.canal = canal; }   // ← 🌉 A PONTE
  enviar(destino, texto) { return this.canal.enviar(destino, texto); }
}

class NotificacaoUrgente extends Notificacao {
  enviar(destino, texto) {
    // Refina o comportamento SEM saber qual canal está do outro lado.
    return this.canal.enviar(destino, `🚨 URGENTE: ${texto.toUpperCase()}`);
  }
}

class NotificacaoAgrupada extends Notificacao {
  constructor(canal) { super(canal); this.fila = []; }
  enviar(destino, texto) { this.fila.push(texto); return null; }
  descarregar(destino) {
    const resumo = `${this.fila.length} avisos:\n• ` + this.fila.join('\n• ');
    this.fila = [];
    return this.canal.enviar(destino, resumo);
  }
}

// 3 canais × 3 políticas = 9 comportamentos com apenas 6 classes.
console.log(new NotificacaoUrgente(new CanalSMS()).enviar('+5511999', 'servidor caiu'));
console.log(new NotificacaoUrgente(new CanalSlack()).enviar('ops', 'servidor caiu'));

const diario = new NotificacaoAgrupada(new CanalEmail());
diario.enviar('ana@x.com', 'backup ok');
diario.enviar('ana@x.com', 'deploy ok');
console.log(diario.descarregar('ana@x.com'));
Na práticaonde ele já existe
  • JDBC: a API é a abstração, os drivers são as implementações
  • Device drivers de sistema operacional
  • React Native / Flutter: mesma API de widget, renderizadores por plataforma

Consequências

A favor
  • Cria classes e apps independentes de plataforma.
  • O cliente enxerga só a abstração de alto nível.
  • Abstração e implementação evoluem separadamente (Aberto/Fechado).
  • Troca a implementação em tempo de execução.
Contra
  • Complica o código quando a classe é coesa e não tem duas dimensões de variação reais.
Use quando
  • Você percebe uma explosão combinatória de subclasses (A × B).
  • Você quer estender uma classe em dimensões ortogonais e independentes.
  • Você precisa trocar a implementação em tempo de execução.
Evite quando
  • Só existe uma implementação e nenhuma previsão de outra.

Relações com outros padrões

parecido / fácil de confundir
Adapter
Bridge é planejada no design; Adapter é remédio aplicado depois.
Strategy
Estruturalmente idênticos (composição + delegação). A intenção difere: Strategy troca ALGORITMOS; Bridge separa DIMENSÕES estruturais.
State
Mesma estrutura, intenção diferente.
costuma andar junto
Abstract Factory
A fábrica pode montar a combinação abstração + implementação correta.

Verificação

Questãoa resposta está marcada

Bridge e Strategy têm praticamente o mesmo diagrama. O que realmente as separa?

  1. A intenção: Bridge separa duas dimensões estruturais que variam; Strategy intercambia algoritmos para uma mesma tarefa
  2. Bridge usa herança e Strategy usa composição
  3. Strategy só funciona com métodos estáticos
  4. Bridge exige no mínimo três implementações concretas

Este é um exemplo clássico de que padrões se distinguem por INTENÇÃO, não por diagrama. A estrutura é a mesma; o problema que resolvem é diferente.