Salve galera!! Tudo certo?

Vamos hoje abordar o último pattern do grupo Estruturais, o Proxy. Neste começo de ano os trabalhos aqui no blog ainda não estão a todo vapor, pois ainda estou fazendo o planejamento de posts, eventos, etc., mas logo mais voltaremos com a programação semanal de posts além de novidades! Aguardem!

Chega de papo, vamos falar sobre o pattern Proxy!

Proxy

O objetivo principal do Proxy é encapsular um objeto através de um outro objeto que possui a mesma interface, de forma que o segundo objeto, conhecido como “Proxy”, controla o acesso ao primeiro, que é o objeto real.

Calma… vamos dar um exemplo para explicar melhor. Imagine que você tem prover acesso a objetos com uma grande quantidade de recursos, como um arquivo grande, uma coleção com muitos itens, mas não deseja instanciar este objeto até que o mesmo seja realmente requisitado pelo sistema. Um exemplo simples, seria carregar um arquivo, apenas na primeira vez que ele for requisitado, e caso seja mais de uma vez, aproveitar o arquivo já carregado.

Fazer isto manualmente implica em incluir vários IF’s ou um método a parte para controlar quando a instância é nula ou não, carregar o arquivo, acaba deixando o código mais complexo e ainda fazendo com que este trecho de código assuma mais responsabilidades do que o necessário, quebrando um dos princípios do SOLID, o Princípio da Responsabilidade Única (S).

Utilizando o Proxy, temos um objeto que implementa a mesma interface que o objeto original implementa, mas fornecendo um controle de acesso a este objeto original, instanciado dentro do Proxy. Toda chamada para o objeto original passa e é controlada pelo objeto Proxy.

Abaixo temos o diagrama UML deste exemplo:

sendo aplicado.

No diagrama acima temos cada um dos itens, com suas responsabilidades descritas, abaixo:

  • Interface Imagem: Interface que define o contrato para nossos objetos, com o método exibir, responsável por exibir dados da imagem no Console.
  • Classe ImagemArquivo: Implementação da interface, com uma propriedade para armazenar o nome do arquivo a ser carregado, a implementação do método para exibir dados da imagem no Console e o método responsável por carregar o arquivo da imagem do disco para a memória.
  • Classe ImagemProxy: Este é o objeto que aplica o padrão Proxy. Ele implementa a mesma interface do objeto ImagemArquivo e possui uma propriedade / variável do tipo ImagemArquivo, para armazenar a instância desta classe. Ao chamar o método exibir, este irá verificar se a variável imagemArquivo já está instânciada, sendo que se estiver, já chama o método exibir() da instância. Caso contrário, irá instanciar a classe ImagemArquivo, adicionar o nome do arquivo, conforme a propriedade definida na classe ImagemProxy e chamar, na sequência, os métodos carregar() e exibir() da instância de ImagemArquivo(). Chamadas feitas após este momento, irão aproveitar esta instância, não gastando tempo novamente com o carregamento do arquivo.
  • Classe ProxyDemo: Aplicação Console que instancia a classe Proxy e utiliza a mesma para exibir dados de uma imagem.

Notem que no exemplo acima, todas as resposabilidades ficaram divididas de forma simples, onde uma classe tem a responsabilidade pelo carregamento e exibição da imagem, outra tem a responsabilidade de controlar este acesso (Proxy) e nosso console que apenas utiliza o Proxy. Nossa classe de Imagem, propriamente dita, e a Console não tem nenhuma lógica para controle de acesso, tornando nosso código, a manutenção do mesmo, mais simples e fácil.

Vamos ver agora ficha resumo do pattern onde podemos conferir a implementação do exemplo em C#, além de alguns detalhes extras como prós e contras no uso deste pattern.

Ficha Resumo

  • Nome: Proxy;
  • Objetivo / intenção: Encapsular um objeto através de um outro objeto que possui a mesma interface, de forma que o segundo objeto, conhecido como “Proxy”, controla o acesso ao primeiro, que é o objeto real;
  • Motivação: Quando temos um controle ou modificações adicionais a serem realizadas durante o acesso a um determinado objeto, precisamos de um modo simples para fazer isso, sem adicionar complexidade / responsabilidade adicional na classe que faz esse acesso.
  • Aplicabilidade: O pattern Proxy é bastante utilizado em aplicações J2EE, onde temos um controle grande sobre o acesso a determinados objetos e funcionalidades da plataforma, e em sistemas onde precisamos controlar o instanciamento de objetos conforme a necessidade, durante a execução do aplicativo, sem adicionar complexidade e responsabilidades adicionais para a classe que faz o acesso.
  • Estrutura: No desenho abaixo, temos um exemplo UML de aplicação do pattern, já descrito no início do artigo com a responsabilidade de cada parte do diagrama:
Exemplo em UML do padrão Proxy sendo aplicado.
  • Consequências: A aplicação do pattern Proxy tem como vantagens a maior eficiência e menor custo de nossa aplicação em termos de processamento, dissociação de clientes da localização de componentes de servidor remoto e a separação do código de limpeza da funcionalidade. Em contrapartida, para alguns casos, sua implementação pode tornar-se complexa e até mesmo diminuir a eficiência do sistema devido uma implementação mal realizada.
  • Implementações: Abaixo temos um exemplo de código em C# para o pattern:
  • Usos conhecidos: O exemplo mais utilizado é quando estamos trabalhando com EJBs na pltaforma J2EE do Java, no uso pelo objeto “javax.ejb.EJBObject”, que representa uma referência remota ao EJB. Para o cliente que está utilizando a interface remote de um EJB, é transparente a chamada remota ao servidor, permitindo que complexos sistemas distribuídos possam ser desenvolvidos como se fossem chamadas locais.
  • Padrões relacionados: O padrão Adapter tem funcionalidade semelhante, mas provendo uma interface diferente para o objeto, enquanto no Proxy utilizamos a mesma interface. O padrão Decorator e o Proxy tem objetivos diferentes, apesar de suas estruturas serem bem semelhantes.

Concluindo

Hoje aprendemos sobre o pattern Proxy, qual sua utilidade e quando aplicar. Um detalhe que temos que ter atenção, até para evitar confusão com os patterns Adapter e Decorator, é que o Proxy e o objeto real que está sendo encapsulado devem implementar a mesma interface.

Por hoje deixo este material para vocês e na semana que vem iniciamos com o grupo de patterns Comportamentais, iniciando pelo pattern Chain of Responsability.

Para quem perdeu a série desde o início, segue o link para a primeira parte, onde listo todos os patterns que vamos abordar, cada um com o link correspondente:

Arquitetura e desenvolvimento de software — Parte 1 — Introdução
Salve galera! Tudo bem?

Um abraço a todos e até a próxima!