1. O que é o Padrão Proxy

O padrão proxy é um padrão de design estrutural que atua como um proxy para controlar o acesso a um objeto específico. Com base no objeto de destino (o objeto sendo proxy), o padrão proxy fornece um objeto proxy através do qual os clientes podem acessar o objeto de destino, permitindo a adição de funcionalidades adicionais ao objeto de destino.

1.1 Definição do Padrão Proxy

O padrão proxy é um padrão de design que envolve a colaboração de dois ou mais objetos. Um objeto é o objeto de destino real que está sendo chamado, enquanto um ou mais outros objetos atuam como objetos proxy. Os objetos proxy interceptam o acesso ao objeto de destino, fornecendo uma forma indireta de acessar o objeto de destino.

1.2 Propósito e Objetivos do Padrão Proxy

O principal propósito do padrão proxy é fornecer uma forma indireta de acessar o objeto de destino, permitindo a adição de funcionalidades adicionais ao objeto de destino. Os objetos proxy podem lidar com lógica comum, como controlar o acesso ao objeto de destino, fazer cache e registrar. O padrão proxy também pode implementar carregamento preguiçoso, instanciando o objeto de destino apenas quando necessário.

2. Características e Vantagens do Padrão Proxy

O padrão proxy possui as seguintes características e vantagens:

  • Pode estender a funcionalidade do objeto de destino sem modificá-lo.
  • Pode controlar o acesso ao objeto de destino por meio do objeto proxy.
  • Pode realizar operações adicionais antes ou depois de acessar o objeto de destino.
  • Pode implementar o carregamento preguiçoso, instanciando o objeto de destino apenas quando necessário.

3. Exemplos de Aplicações Práticas do Padrão Proxy

O padrão proxy é amplamente utilizado em muitos cenários de aplicação. Aqui estão alguns exemplos comuns de aplicações práticas:

  • Proxy Remoto: Usado para acessar objetos na rede localmente.
  • Proxy Virtual: Usado para criar objetos caros conforme necessário.
  • Proxy de Segurança: Usado para controlar o acesso a objetos.
  • Referência Inteligente: Usado para realizar operações adicionais ao acessar objetos, como contagem de objetos.

4.1 Diagrama de Classe UML

O seguinte é o diagrama de classe UML do Padrão Proxy em Golang:

Padrão Proxy em Golang

4.2 Introdução do Exemplo

Suponha que temos uma interface Subject que define um método Request. Temos uma classe de implementação concreta RealSubject, que implementa a interface Subject. Em seguida, criamos uma classe de proxy Proxy, que contém um objeto RealSubject e também implementa a interface Subject. No método Request da classe Proxy, podemos realizar operações adicionais antes ou depois de chamar o método Request de RealSubject.

4.3 Passo 1 de Implementação: Definir a Interface do Proxy

Primeiro, precisamos definir uma interface Subject que contenha um método Request:

package main

type Subject interface {
    Request()
}

4.4 Passo 2 de Implementação: Implementar o Objeto de Destino

Em seguida, implementamos o objeto de destino específico RealSubject, que implementa a interface Subject:

package main

import "fmt"

type RealSubject struct {}

func (r *RealSubject) Request() {
    fmt.Println("RealSubject: Lidando com o Pedido")
}

4.5 Passo 3 de Implementação: Implementar o Objeto Proxy

A seguir, criamos um objeto proxy, Proxy, que contém um objeto RealSubject e implementa a interface Subject. No método Request do Proxy, podemos realizar algumas operações extras antes ou depois de chamar o método Request do RealSubject:

package main

import "fmt"

type Proxy struct {
    realSubject *RealSubject
}

func (p *Proxy) Request() {
    fmt.Println("Proxy: Pré-Requisição")
    
    if p.realSubject == nil {
        p.realSubject = &RealSubject{}
    }
    
    p.realSubject.Request()
    
    fmt.Println("Proxy: Pós-Requisição")
}

4.6 Passo 4 de Implementação: Invocando o Objeto Proxy

Por fim, podemos usar o objeto proxy, Proxy, para invocar os métodos do objeto proxy, RealSubject:

package main

func main() {
    proxy := Proxy{}
    proxy.Request()
}

A execução do código acima produzirá a saída:

Proxy: Pré-Requisição
RealSubject: Lidando com o Pedido
Proxy: Pós-Requisição

5.1 A Diferença e Conexão entre o Padrão de Proxy e o Padrão de Decorator

Tanto o padrão de proxy quanto o padrão de decorator são padrões de design estrutural, ambos contendo um objeto alvo e um objeto de proxy/decorator. No entanto, existem algumas diferenças entre os dois:

  • O padrão de proxy geralmente envolve controle de acesso ao objeto alvo, enquanto o padrão de decorator foca mais em estender o objeto alvo.
  • O padrão de proxy geralmente realiza operações adicionais antes ou depois do objeto alvo, enquanto o padrão de decorator adiciona dinamicamente funcionalidades extras sobre o objeto alvo.

5.2 Comparação entre Proxy Estático e Proxy Dinâmico

O padrão de proxy pode ser dividido em proxy estático e proxy dinâmico. O proxy estático determina o tipo do objeto de proxy em tempo de compilação, e o objeto de proxy é escrito manualmente pelo programador. O proxy dinâmico, por outro lado, gera dinamicamente o objeto de proxy em tempo de execução com base na interface do objeto alvo. O proxy dinâmico é mais flexível, mas também mais complexo em comparação com sua contraparte estática.

5.3 Aplicação do Padrão de Proxy em Microservices

O padrão de proxy pode ser aplicado em uma arquitetura de microservices. Por exemplo, podemos usar um proxy para encapsular o acesso a outros microservices e implementar mecanismos como balanceamento de carga, limite de taxa e quebra de circuito na camada de proxy. Isso pode melhorar a confiabilidade e o desempenho do sistema. O padrão de proxy também pode ser usado para implementar funcionalidades de descoberta de serviço e roteamento.