Bridge
O Bridge é um padrão estrutural que separa uma abstração da sua implementação.
Isso permite que ambas evoluam independentemente.
Imagine um sistema de notificações.
Temos diferentes tipos de notificação:
Email
SMS
Push
E diferentes serviços:
SendGrid
Twilio
Firebase
Se combinarmos tudo diretamente, teremos muitas classes:
EmailSendGrid
EmailTwilio
EmailFirebase
SmsSendGrid
SmsTwilio
SmsFirebase
PushSendGrid
PushTwilio
PushFirebase
Isso gera uma explosão de combinações.
O Bridge separa as duas dimensões.
Implementação
Criamos a implementação:
interface NotificationSender {
send(
message: string
): void;
}
Implementações:
class EmailSender
implements NotificationSender {
send(message: string) {
console.log(
`Email: ${message}`
);
}
}
class SmsSender
implements NotificationSender {
send(message: string) {
console.log(
`SMS: ${message}`
);
}
}
Agora criamos a abstração:
abstract class Notification {
constructor(
protected sender:
NotificationSender
) {}
abstract notify(
message: string
): void;
}
Implementação:
class AlertNotification
extends Notification {
notify(message: string) {
this.sender.send(
`ALERTA: ${message}`
);
}
}
Agora podemos combinar livremente:
const emailAlert =
new AlertNotification(
new EmailSender()
);
emailAlert.notify(
"Servidor offline"
);
Ou:
const smsAlert =
new AlertNotification(
new SmsSender()
);
smsAlert.notify(
"Servidor offline"
);
Estrutura
Abstração
│
├── Notification
│
↓
Implementação
│
├── EmailSender
└── SmsSender
As duas hierarquias podem evoluir separadamente.
Quando usar?
Bridge é útil quando:
- Existem duas dimensões independentes de variação.
- A quantidade de combinações está crescendo.
- Queremos evitar uma explosão de subclasses.
- Abstração e implementação precisam evoluir separadamente.
A ideia principal é:
Separar "o que algo faz" de "como algo faz".