Diferença entre os padrões Adapter e Proxy

Quando a utilização dos padröes Adapter e Proxy do GoF, é comum algumas confusões sobre suas aplicações. São padrões que ajudam a resolver vários problemas, oferecem a flexibilidade de mudar a composição em tempo de execução.
Os dois padrões possuem princípios semelhantes, de encapsular a utilização de um serviço. Mas os objetivos de cada um são diferentes.
O Adapter é um padrão estrutural utilizado quando a classe/interface de um serviço não possui a interface da maneira que o cliente espera e que não pode ser alterada. Sendo assim, é criado uma classe que converte uma existente para nova interface. É um padrão normalmente aplicado em sistemas legados, ou pra desacoplar algum framework.

Nesse exemplo, ao invés do cliente utilizar a classe GeradorLegado, ele utiliza a interface Gerador e a classe GeradorAdapter. Futuramente, quando o GeradorLegado for descartado, basta a nova classe implementar a interface Gerador.

O Proxy é uma classe que funciona como interface de um serviço para a classe cliente. Tem a característica e o objetivo de alterar o comportamento da classe de serviço implementada. Pode ser utilizada em vários casos como conexões de redes, tratamento de arquivos e inclusive em conjunto com o padrão DAO pra logs de auditoria.

No exemplo, o cliente faz uso da interface Gerador, que pode ser uma instância do GeradorProxy, o qual vai utilizar o método do GeradorImpl que é a classe de serviço, mas vai alterar o comportamento (com rotinas antes ou/e depois da utilização do metodo gerarAlgo() do serviço).
A principal diferença entre os padrões é que proposta do proxy é de alterar o comportamento do serviço mas preservar a interface, enquanto o Adapter muda a interface do serviço e preserva seu comportamento.
O cliente pode usar o Proxy ou diretamente o serviço (principalmente usando injeção de dependências), pois ambos implementam a mesma interface e, já com o Adapter o cliente vai sempre usar o Adaptador.
No uso do Adapter, geralmente é quando um serviço já esta definido e implementado e deve ser utilizado. No caso do Proxy, tanto o serviço quanto a interface pode já estar definida e sendo utilizada, mas é necessário alterar o comportamento do serviço, sem alterar sua implementação.

Apache httpd 2 e Tomcat com AJP

Uma das maneiras de integrar o apache http com o Tomcat (ou outro servidor como Jetty, Jboss, Glassfish, …) é usando o proxy protocolo AJP, onde permite que o apache receba a requisição e a repasse para o tomcat, o qual pode, inclusive ficar em uma rede interna, atrás de um firewall.

Como exemplo dessa integração, segue os passos:

No apache, cria-se um novo arquivo em /etc/apache2/sites-available/ com um nome qualquer (ex. ajp_tomcat), com o seguinte conteudo:


Listen 9000
NameVirtualHost *:9000
<VirtualHost *:9000>
ServerName localhost
ErrorLog /var/log/apache2/ajp.error.log
CustomLog /var/log/apache2/ajp.log combined
<Proxy *>
AddDefaultCharset Off
Order deny,allow
Allow from all
</Proxy>
ProxyPass / ajp://localhost:8009/
ProxyPassReverse / ajp://localhost:8009/
</VirtualHost>

Onde:

  • 9000 é a porta que o apache vai atender as requisições a ser passadas para o tomcat.
  • ajp://localhost:8009/ é o servidor onde está o tomcat rodando (no caso na mesma máquina do httpd) e porta do AJP que é configurada em server.xml (padrão é 8009)

Agora precisa carregar o modulo de proxy do ajp do httpd.
# a2enmod proxy_ajp

E agora habilitar a configuração do arquivo criado.
# a2ensite ajp_tomcat

Pronto, agora só reiniciar o httpd.
# /etc/init.d/apache2 force-reload

E acessar http://localhost:9000/

Pode-se usar desse recurso para, por exemplo, fazer o tomcat escutar na porta 80, configurando por domínio/subdomínio específico. Outra utilização desse recurso é para fazer balanceamento de carga para requisições no servidor de aplicações.