Pular para o conteúdo
Estruturais

Proxy

Fornece um substituto ou placeholder para outro objeto para controlar o acesso a ele.

Intenção

Introduzir um objeto substituto que controla o acesso a um sujeito real -- adiando sua criação, protegendo suas operações, ou adicionando preocupações transversais -- enquanto apresenta a mesma interface, de forma que os clientes não consigam notar a diferença.

Problema

Você tem um objeto que é caro de criar, está localizado em um servidor remoto, ou exige controle de acesso. Permitir acesso direto irrestrito desperdiça recursos, compromete segurança, ou acopla o cliente a detalhes de infraestrutura. Você precisa de uma forma de interpor lógica de controle sem alterar o cliente ou o objeto real.

Solução

Crie uma classe proxy que implementa a mesma interface do sujeito real. O proxy mantém uma referência (ou a cria preguiçosamente) ao sujeito real e encaminha requisições a ele, adicionando comportamento como inicialização preguiçosa, verificações de acesso, logging, ou cache ao redor de cada delegação.

Participantes

  • Subject -- a interface comum compartilhada por RealSubject e Proxy
  • RealSubject -- o objeto real que executa o trabalho
  • Proxy -- controla o acesso ao RealSubject; implementa a mesma interface
  • Client -- trabalha com a interface Subject, sem saber se está lidando com um Proxy ou com o RealSubject

Vantagens

  • Controla o acesso ao objeto real sem que os clientes saibam
  • Permite inicialização preguiçosa de objetos pesados (virtual proxy)
  • Pode adicionar cache, logging, ou controle de acesso de forma transparente
  • O ciclo de vida do objeto real pode ser gerenciado independentemente do cliente

Desvantagens

  • Adiciona uma camada extra de indireção, o que pode complicar a depuração
  • O tempo de resposta pode aumentar devido a processamento adicional no proxy
  • O código do proxy pode ficar complexo ao combinar múltiplas preocupações (cache + auth + logging)
  • O proxy precisa se manter sincronizado com a evolução da interface do sujeito real

Analogia do mundo real

Um cartão de crédito é um proxy para sua conta bancária. A loja (cliente) passa o cartão (proxy) em vez de acessar seu dinheiro (sujeito real) diretamente. O cartão faz o controle de acesso (verificação de PIN), se comunica com o banco, e pode aplicar limites de gasto -- tudo antes de deixar a transação passar.

Casos de uso

  • Virtual proxy: adiar o carregamento de uma imagem de alta resolução até que ela entre na área visível
  • Protection proxy: checar permissões do usuário antes de permitir operações em um recurso sensível
  • Caching proxy: armazenar resultados de consultas caras ao banco de dados e retornar dados em cache em chamadas repetidas
  • Remote proxy: representar um objeto em um servidor diferente e encapsular chamadas pela rede
  • Logging proxy: registrar cada invocação de método para fins de auditoria ou depuração

Exemplos de código

Image.java
interface Image {
    void display();
    String getFilename();
}

final class HighResImage implements Image {
    private final String filename;
    private final String data;

    HighResImage(String filename) {
        this.filename = filename;
        // Simulate expensive loading
        this.data = "[binary data of " + filename + "]";
        System.out.println("Loaded " + filename + " from disk (expensive!)");
    }

    @Override
    public void display() {
        System.out.println("Displaying " + filename);
    }

    @Override
    public String getFilename() {
        return filename;
    }
}

// Virtual Proxy -- defers creation until actually needed
final class LazyImageProxy implements Image {
    private final String filename;
    private HighResImage realImage;

    LazyImageProxy(String filename) {
        this.filename = filename;
    }

    @Override
    public void display() {
        if (realImage == null) {
            realImage = new HighResImage(filename);
        }
        realImage.display();
    }

    @Override
    public String getFilename() {
        return filename;
    }
}

// Protection Proxy -- checks permissions before delegating
final class ProtectedImageProxy implements Image {
    private final Image target;
    private final boolean isAdmin;

    ProtectedImageProxy(Image target, boolean isAdmin) {
        this.target = target;
        this.isAdmin = isAdmin;
    }

    @Override
    public void display() {
        if (!isAdmin) {
            System.out.println("Access denied to " + target.getFilename());
            return;
        }
        target.display();
    }

    @Override
    public String getFilename() {
        return target.getFilename();
    }
}

public class ProxyDemo {
    public static void main(String[] args) {
        Image image = new LazyImageProxy("sunset.png");
        System.out.println("Proxy created, image not loaded yet");
        image.display(); // loads here, on first access
        image.display(); // reuses cached instance
    }
}

Um virtual proxy que carrega preguiçosamente um objeto de imagem pesado no primeiro acesso, e um protection proxy que verifica permissões antes de delegar operações.