Padrões de Projeto em Java: da teoria à prática
Padrões de Projeto (Design Patterns) são soluções comprovadas para problemas típicos no desenvolvimento de software. Para um desenvolvedor Java, conhecer padrões não é apenas uma vantagem, mas uma necessidade. Eles permitem escrever código flexível, sustentável e escalável. Neste artigo, vamos analisar quatro padrões-chave do catálogo GoF (Gang of Four) com exemplos reais em Java.
Por que os padrões são importantes para o desenvolvedor Java?
Java é uma linguagem fortemente tipada e orientada a objetos, onde os padrões ajudam a:
- Reduzir o acoplamento do código — classes dependem de abstrações, não de implementações concretas.
- Aumentar a reutilização — soluções prontas se adaptam facilmente a novas tarefas.
- Simplificar o trabalho em equipe — padrões são uma linguagem comum para desenvolvedores.
1. Singleton
O padrão Singleton garante que uma classe tenha apenas uma instância e fornece um ponto de acesso global a ela. Em Java, a implementação clássica é assim:
public class DatabaseConnection { private static volatile DatabaseConnection instance; private String connectionString;
private DatabaseConnection(String connectionString) { this.connectionString = connectionString; }
public static DatabaseConnection getInstance(String connectionString) { if (instance == null) { synchronized (DatabaseConnection.class) { if (instance == null) { instance = new DatabaseConnection(connectionString); } } } return instance; }
public void connect() { System.out.println("Connected to: " + connectionString); }}Quando usar Singleton?
- Gerenciamento de conexão com banco de dados.
- Loggers e gerenciadores de configuração.
- Pool de threads (Thread Pool).
Importante: Em aplicações Java modernas, o Singleton é frequentemente substituído pela injeção de dependência (contêineres DI, Spring).
2. Factory Method
O Factory Method define uma interface para criar um objeto, mas permite que as subclasses decidam qual classe instanciar. Vejamos um exemplo de criação de notificações:
// Interface do produtointerface Notification { void send(String message);}
// Produtos concretosclass EmailNotification implements Notification { @Override public void send(String message) { System.out.println("Sending Email: " + message); }}
class SMSNotification implements Notification { @Override public void send(String message) { System.out.println("Sending SMS: " + message); }}
// Fábricaabstract class NotificationFactory { public abstract Notification createNotification();
public void notifyUser(String message) { Notification notification = createNotification(); notification.send(message); }}
class EmailNotificationFactory extends NotificationFactory { @Override public Notification createNotification() { return new EmailNotification(); }}
class SMSNotificationFactory extends NotificationFactory { @Override public Notification createNotification() { return new SMSNotification(); }}
// Usopublic class Main { public static void main(String[] args) { NotificationFactory factory = new EmailNotificationFactory(); factory.notifyUser("Hello, User!"); }}Vantagens do Factory Method:
- O código não depende de classes concretas.
- Adicionar novos tipos de notificação não requer alteração no código existente (princípio Open/Closed).
- Simplifica o teste de unidade