O padrão de design Proxy tem como objetivo principal atuar como um substituto ou intermediário para outro objeto, controlando o acesso a ele.
Esse padrão é usado para resolver uma variedade de problemas relacionados à gestão de recursos e controle de acesso, e é particularmente útil em situações como:
-
Controle de Acesso: O Proxy pode controlar o acesso ao objeto original, permitindo realizar operações adicionais, como autenticação, verificação de permissões, ou outras lógicas de segurança antes de permitir o acesso ao objeto.
-
Atraso na Criação de Objetos Pesados (Lazy Initialization): Em casos onde a criação de um objeto é custosa em termos de recursos, o Proxy pode atrasar a criação e inicialização desse objeto até que ele seja realmente necessário.
-
Gerenciamento de Recursos para Objetos Remotos (Remote Proxy): Em sistemas distribuídos, o Proxy pode facilitar a interação com objetos que residem em diferentes endereços de memória ou até mesmo em diferentes máquinas.
-
Registro e Auditoria: O Proxy pode ser usado para registrar ou auditar as chamadas feitas ao objeto original, fornecendo uma forma de acompanhar as interações com o objeto sem modificar seu código.
-
Referência Inteligente: O Proxy pode adicionar funcionalidades quando um objeto é acessado, como contar o número de referências ao objeto, carregar um objeto na memória quando ele é acessado pela primeira vez, ou liberar recursos quando o objeto não é mais necessário.
-
Proteção e Restrição de Funcionalidades: O Proxy pode permitir a execução de certas operações enquanto restringe outras, protegendo o objeto original de usos inadequados ou perigosos.
Existem diferentes tipos de Proxies, como o Proxy Virtual, Proxy Remoto, Proxy de Proteção e Proxy Inteligente, cada um adaptado para resolver problemas específicos em diferentes contextos. O padrão Proxy é uma ferramenta poderosa para gerenciar o acesso e o ciclo de vida de objetos, proporcionando uma camada adicional de controle e abstração entre o cliente e o objeto real.
Exemplo de implementação
Vamos criar um exemplo de um Proxy que realiza a auditoria das chamadas feitas a um objeto original. Neste caso, o Proxy irá registrar cada chamada de método ao serviço real, permitindo o monitoramento e a análise dessas chamadas. Vou usar uma interface simples de um serviço que executa uma operação, e o Proxy irá registrar detalhes sobre quando e como as operações são chamadas.
Definindo a Interface do Serviço
public interface ServicoOperacao {
void executarOperacao(String operacao);
}Implementando o Serviço Real
public class ServicoOperacaoReal implements ServicoOperacao {
@Override
public void executarOperacao(String operacao) {
System.out.println("Executando operação: " + operacao);
// Implementação real da operação
}
}Implementando o Proxy de Auditoria
import java.util.Date;
public class ProxyAuditoria implements ServicoOperacao {
private ServicoOperacao servicoReal;
public ProxyAuditoria(ServicoOperacao servicoReal) {
this.servicoReal = servicoReal;
}
@Override
public void executarOperacao(String operacao) {
// Registro de auditoria antes de chamar o método real
System.out.println("Auditoria - Chamando operação: " + operacao + " em " + new Date());
servicoReal.executarOperacao(operacao);
// Registro de auditoria após a chamada do método
System.out.println("Auditoria - Operação executada: " + operacao + " em " + new Date());
}
}Utilizando o Proxy de Auditoria no Sistema
public class Main {
public static void main(String[] args) {
ServicoOperacao servicoOperacaoReal = new ServicoOperacaoReal();
ServicoOperacao servicoAuditoria = new ProxyAuditoria(servicoOperacaoReal);
servicoAuditoria.executarOperacao("Operacao1");
servicoAuditoria.executarOperacao("Operacao2");
}
}