Skip to content

Latest commit

 

History

History
155 lines (120 loc) · 5.07 KB

File metadata and controls

155 lines (120 loc) · 5.07 KB

Proxy

O que é?

O Proxy é um padrão estrutural que permite fornecer um substituto ou placeholder para outro objeto. Um proxy controla o acesso ao objeto original, permitindo que você faça algo antes ou depois do pedido chegar ao objeto original.

Quando usar?

  • Lazy loading: quando você tem um objeto pesado que consome recursos e nem sempre é necessário
  • Controle de acesso: quando você quer que apenas clientes específicos possam acessar o objeto
  • Execução local de serviço remoto: quando o objeto real está em outro servidor
  • Logging: quando você precisa manter um registro de acessos ao objeto
  • Caching: quando você precisa armazenar em cache resultados de operações custosas

Exemplo em Python

from abc import ABC, abstractmethod
from typing import Dict
import time

# Interface comum
class BancoDados(ABC):
    @abstractmethod
    def consultar(self, query: str) -> Dict:
        pass

    @abstractmethod
    def executar(self, comando: str) -> bool:
        pass

# Objeto Real
class BancoDadosReal(BancoDados):
    def __init__(self):
        # Simulando uma conexão pesada
        print("Inicializando conexão com o banco de dados...")
        time.sleep(1)
        self.conectado = True
    
    def consultar(self, query: str) -> Dict:
        if not self.conectado:
            raise Exception("Banco de dados não está conectado!")
        print(f"Executando query: {query}")
        # Simulando uma consulta
        return {"dados": f"Resultados para {query}"}
    
    def executar(self, comando: str) -> bool:
        if not self.conectado:
            raise Exception("Banco de dados não está conectado!")
        print(f"Executando comando: {comando}")
        # Simulando execução de comando
        return True

# Proxy
class BancoDadosProxy(BancoDados):
    def __init__(self):
        self._banco_dados = None
        self._cache: Dict[str, Dict] = {}
    
    def _conectar(self):
        """Lazy initialization do banco de dados real"""
        if self._banco_dados is None:
            self._banco_dados = BancoDadosReal()
    
    def consultar(self, query: str) -> Dict:
        print(f"Proxy: Verificando cache para query: {query}")
        
        # Verifica cache primeiro
        if query in self._cache:
            print("Proxy: Retornando resultado do cache")
            return self._cache[query]
        
        # Se não está em cache, conecta ao banco se necessário
        self._conectar()
        
        # Executa a query e armazena em cache
        resultado = self._banco_dados.consultar(query)
        self._cache[query] = resultado
        
        return resultado
    
    def executar(self, comando: str) -> bool:
        print(f"Proxy: Verificando permissão para executar: {comando}")
        
        # Aqui poderia ter verificação de permissões
        if "DROP" in comando.upper():
            raise Exception("Proxy: Comando DROP não permitido!")
        
        self._conectar()
        return self._banco_dados.executar(comando)

# Cliente
class Aplicacao:
    def __init__(self, banco: BancoDados):
        self.banco = banco
    
    def fazer_consulta(self, query: str):
        try:
            resultado = self.banco.consultar(query)
            print(f"Aplicação recebeu: {resultado}\n")
        except Exception as e:
            print(f"Erro: {e}\n")
    
    def executar_comando(self, comando: str):
        try:
            sucesso = self.banco.executar(comando)
            print(f"Comando executado com sucesso: {sucesso}\n")
        except Exception as e:
            print(f"Erro: {e}\n")

# Exemplo de uso
def main():
    # Criando o proxy
    banco_proxy = BancoDadosProxy()
    
    # Criando a aplicação
    app = Aplicacao(banco_proxy)
    
    # Fazendo consultas
    app.fazer_consulta("SELECT * FROM usuarios")
    # Segunda vez usa cache
    app.fazer_consulta("SELECT * FROM usuarios")
    
    # Executando comandos
    app.executar_comando("INSERT INTO usuarios VALUES ('João')")
    # Comando não permitido
    app.executar_comando("DROP TABLE usuarios")

if __name__ == "__main__":
    main()

Vantagens

  1. Controle sobre o objeto real sem os clientes saberem
  2. Gerenciamento do ciclo de vida do objeto real
  3. Funciona mesmo quando o objeto real não está pronto ou disponível
  4. Adiciona comportamentos sem alterar o objeto real
  5. Princípio Aberto/Fechado: pode introduzir novos proxies sem mudar código existente

Desvantagens

  1. Pode aumentar a complexidade do código
  2. Pode introduzir atraso na resposta quando inicializa sob demanda
  3. Alguns padrões de proxy podem tornar o comportamento menos previsível
  4. Pode dificultar o debugging em alguns casos

Considerações de Implementação

  • Escolha o tipo de proxy adequado para seu caso (virtual, proteção, cache, etc.)
  • Mantenha a interface do proxy idêntica à do objeto real
  • Considere usar Factory Method para criar proxies
  • Em Python, você pode usar __getattr__ para encaminhar chamadas automaticamente
  • Considere o impacto na performance ao adicionar camadas de proxy
  • Documente claramente o comportamento adicional que o proxy introduz