Pular para o conteúdo

Atividade 08: Bridge

Para cada cenário abaixo, indique se o padrão Bridge é apropriado ou não e justifique em 2–3 frases.

  1. Um sistema de notificações que precisa variar em duas dimensões: o tipo de conteúdo (informativo, alerta, promoção) e o canal de envio (SMS, e-mail, push). Sem o padrão, cada combinação viraria uma classe nova.
  2. Uma aplicação multiplataforma que precisa rodar a mesma lógica sobre APIs de sistema operacional diferentes (Windows, Linux, macOS), sem multiplicar as classes da interface.
  3. Um módulo de persistência em que a mesma lógica de repositório precisa funcionar com MySQL ou PostgreSQL, podendo até trocar de banco em tempo de execução.
  4. Um framework de testes que precisa executar testes em diferentes ambientes com diferentes configurações de hardware.

Para cada item, responda:

  • “Faz sentido usar Bridge” ou “Não faz sentido usar Bridge”.
  • Explique rapidamente o porquê (duas dimensões ortogonais, explosão de subclasses, plataforma, overengineering, etc.).

Crie uma analogia própria para explicar o padrão Bridge para alguém que não é da área de TI.

Na aula, usamos o carro e o motor: dirigir um carro não depende do motor (combustão ou elétrico), o carro delega a força ao motor, e carros e motores evoluem independentes. Agora crie uma outra analogia.

Descreva uma situação do mundo real em que:

  • existam duas “famílias” que precisam ser combinadas de muitas formas,
  • combinar tudo de uma vez por “duplicação” seja inviável,
  • e cada família possa evoluir separadamente, com as combinações feitas na hora (composição).

Considere o código Java abaixo, usado em um editor gráfico:

public abstract class Forma {
public abstract void desenhar();
}
public class CirculoVermelho extends Forma {
@Override
public void desenhar() {
System.out.println("Desenhando círculo vermelho");
// lógica de desenhar círculo + lógica da cor vermelho
}
}
public class CirculoAzul extends Forma {
@Override
public void desenhar() {
System.out.println("Desenhando círculo azul");
// mesma lógica de círculo, cor azul
}
}
public class QuadradoVermelho extends Forma {
@Override
public void desenhar() {
System.out.println("Desenhando quadrado vermelho");
}
}
public class QuadradoAzul extends Forma {
@Override
public void desenhar() {
System.out.println("Desenhando quadrado azul");
}
}

Responda:

  1. Por que essa hierarquia (uma classe por combinação de forma × cor) é um problema de design?
  2. O que acontece ao adicionar uma nova forma (ex.: Triangulo) ou uma nova cor (ex.: Verde)? Quantas classes existiriam para N formas e M cores?
  3. Proponha uma solução usando o padrão Bridge, explicando em linhas gerais: as duas hierarquias (forma e cor), como a Forma passaria a referenciar uma Cor e por que cada lado passaria a evoluir de forma independente.

Acesse os seguintes arquivos em um projeto open source:

O JavaFX separa a lógica de um controle da sua aparência usando o padrão Bridge: o Control (a abstração) guarda uma referência a uma Skin (a implementação) e delega a ela a renderização. Cada controle tem a sua própria skin (por exemplo, o Button usa um ButtonSkin). Quando o Control precisa da skin e ela ainda não existe, ele chama createDefaultSkin(). É a mesma estrutura do ControleRemoto que delega a um Dispositivo vista em aula.

Responda:

  1. Quais são as duas hierarquias do padrão nesse exemplo? Onde está a abstração e onde está a implementação?
  2. Em Button.java, localize o método createDefaultSkin(). O que ele retorna? Por que o Button delega a própria aparência a um ButtonSkin em vez de embutir todo o desenho no próprio controle?

Imagine que você foi contratado para criar o sistema de veículos de uma concessionária.

O sistema precisa montar veículos combinando dois conceitos que evoluem de forma independente:

  • o tipo de veículo (por exemplo, Sedan e SUV), e
  • o tipo de motor (por exemplo, MotorGasolina e MotorEletrico).

Sem o padrão, cada combinação viraria uma classe nova (SedanGasolina, SedanEletrico, SuvGasolina…).

Implemente, em Java, um sistema que separe as duas hierarquias, usando o padrão Bridge.

  1. Crie a interface de implementação Motor:
    • Métodos: void ligar() e void acelerar().
  2. Crie as implementações concretas:
    • MotorGasolina e MotorEletrico, cada um imprimindo mensagens que identificam o motor.
  3. Crie a classe abstrata Veiculo (a abstração):
    • Um campo protected Motor motor (recebido no construtor).
    • Métodos void dirigir() (liga o motor) e void acelerar() (delega ao motor).
  4. Crie as abstrações refinadas:
    • Sedan e Suv, que estendem Veiculo (cada uma pode imprimir o próprio tipo ao dirigir).
  5. Crie uma classe de teste, por exemplo Main, que:
    • Monte as quatro combinações (Sedan com MotorGasolina, Sedan com MotorEletrico, Suv com MotorGasolina, Suv com MotorEletrico) e as execute.
    • Mostre que o mesmo veículo funciona com motores diferentes e que o mesmo motor funciona em veículos diferentes.
    • Explique, em um comentário ou README, como adicionar um novo motor (ex.: MotorHibrido) ou um novo veículo (ex.: Picape) exigiria apenas uma nova classe, sem alterar o outro lado.