Padrões de projeto avançados em Java: de Bridge a Visitor
\n\nPadrões de projeto são soluções comprovadas para problemas típicos de arquitetura de software. Se os padrões básicos (Singleton, Factory, Observer) são familiares a todo desenvolvedor Java, os padrões avançados muitas vezes ficam de fora. Neste artigo, vamos analisar três padrões poderosos: Bridge, Visitor e Memento. Você aprenderá quando aplicá-los e obterá exemplos prontos de código em Java.
\n\n1. Bridge (Ponte) — separando abstração da implementação
\n\nO padrão Bridge é usado quando é necessário separar a abstração e sua implementação, para que possam variar independentemente. Isso é especialmente útil quando você tem múltiplas dimensões de variação (por exemplo, diferentes tipos de dispositivos e diferentes controles remotos).
\n\nQuando aplicar: quando você deseja evitar uma "explosão de classes" devido à combinação de diferentes variantes.
\n\nExemplo: Controle de dispositivos
\n\nImagine que temos controles remotos (Remote) e dispositivos (Device). Queremos que um único controle remoto possa funcionar com diferentes dispositivos (TV, Rádio).
\n\n// Implementação (Device)\ninterface Device {\n void turnOn();\n void turnOff();\n void setVolume(int percent);\n}\n\nclass TV implements Device {\n @Override\n public void turnOn() { System.out.println("TV ligada"); }\n @Override\n public void turnOff() { System.out.println("TV desligada"); }\n @Override\n public void setVolume(int percent) { System.out.println("Volume da TV: " + percent + "%"); }\n}\n\nclass Radio implements Device {\n @Override\n public void turnOn() { System.out.println("Rádio ligado"); }\n @Override\n public void turnOff() { System.out.println("Rádio desligado"); }\n @Override\n public void setVolume(int percent) { System.out.println("Volume do Rádio: " + percent + "%"); }\n}\n\n// Abstração (Remote)\nabstract class Remote {\n protected Device device;\n\n public Remote(Device device) {\n this.device = device;\n }\n\n public abstract void togglePower();\n public abstract void volumeUp();\n public abstract void volumeDown();\n}\n\nclass BasicRemote extends Remote {\n private boolean isOn = false;\n private int volume = 10;\n\n public BasicRemote(Device device) {\n super(device);\n }\n\n @Override\n public void togglePower() {\n if (isOn) { device.turnOff(); isOn = false; }\n else { device.turnOn(); isOn = true; }\n }\n\n @Override\n public void volumeUp() {\n volume += 5;\n device.setVolume(volume);\n }\n\n @Override\n public void volumeDown() {\n volume -= 5;\n device.setVolume(volume);\n }\n}\n\n// Uso\npublic class BridgeDemo {\n public static void main(String[] args) {\n Device tv = new TV();\n Remote remote = new BasicRemote(tv);\n remote.togglePower(); // TV ligada\n remote.volumeUp(); // Volume da TV: 15%\n\n Device radio = new Radio();\n remote = new BasicRemote(radio);\n remote.togglePower(); // Rádio ligado\n remote.volumeUp(); // Volume do Rádio: 15%\n }\n}\n\nVantagem: podemos adicionar novos tipos de dispositivos ou novos controles remotos sem modificar o código existente. O padrão Bridge é ideal para aplicações multiplataforma (por exemplo, UI em diferentes SOs).
\n\n2. Visitor (Visitante) — novas operações sem alterar classes
\n\nO padrão Visitor permite adicionar novas operações a um grupo de objetos sem modificar as próprias classes desses objetos. Esta é uma forma clássica de contornar as limitações de despacho único em Java.
\n\nQuando aplicar: quando você tem uma hierarquia de classes estável, mas frequentemente adiciona novas operações (por exemplo, exportação para diferentes formatos, geração de relatórios).
\n\nExemplo: Exportação de formas para diferentes formatos
\n\nTemos formas