Páginas

domingo, 23 de dezembro de 2012

Ganhe Reusabilidade com Front Controller e Padronização com Command




No post anterior introduzimos os padrões de projetos. Neste post explicaremos dois deles: Front Controller e Command.

O padrão Front Controller é a base de muitos frameworks que conhecemos. Trata-se de uma maneira de centralizar os acessos em um único ponto e então, a partir deste,  rotear para uma ação (ou comando). Isso tem algumas vantagens. Em todas as aplicações existem funcionalidades que devem ser executadas em todos os acessos. Por exemplo verificar se o usuário está logado, verificar permissões e registrar log de acesso. São funções que devem ser executadas não importa qual a funcionalidade acessada. 

Vamos imaginar um cenário sem o front controller com command para entendermos a necessidade de sua implantação em nossos sistemas:

Certa aplicação em java possui 2 Servlets. Um para atualizar um produto e outro para deletar um produto. Em ambas as ações o usuário precisa estar logado, também é preciso registrar um log de acesso.

O primeiro Servlet foi escrito assim:

package servlets;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class AlterarProduto extends HttpServlet {
    
    protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //VERIFICA SE O USUARIO ESTÁ LOGADO
        //REGISTRA LOG DE ACESSO

        //PROCEDE COM A ALTERAÇÃO DO PRODUTO
    }
    
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }
   
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }
   
    @Override
    public String getServletInfo() {
        return "Short description";
    }
}

E o segundo foi escrito assim:

package servlets;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class DeletarProduto extends HttpServlet {
    
    protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //VERIFICA SE O USUARIO ESTÁ LOGADO
        //REGISTRA LOG DE ACESSO

        //PROCEDE COM A EXCLUSÃO DO PRODUTO
    }
    
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }
   
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }
   
    @Override
    public String getServletInfo() {
        return "Short description";
    }
}


Há uma duplicação de código referente a verificação do usuário logado e o registro de log. E se precisarmos mudar algum código referentes a essas funcionalidades? teríamos que mudar todos os servlets. E se precisarmos adicionar mais alguma funcionalidade comum a todos os servlets? novamente teremos que alterar todos. Esse é um dos problemas que o front controller resolve.

Vamos ver como poderia ficar o nosso controller:

package servlets;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class Controller extends HttpServlet {
    
    protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //VERIFICA SE O USUARIO ESTÁ LOGADO
        //REGISTRA LOG DE ACESSO

        //ENCAMINHA PARA  AÇÃO (OU COMANDO) ESPECIALIZADO
    }
    
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }
   
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }
   
    @Override
    public String getServletInfo() {
        return "Short description";
    }
}

Nesse modelo, as requisições 'alterar produto' e 'excluir produto' serão feitas ao mesmo servlet: Controller. Então o Controller depois de executar as funcionalidades comum as duas requisições irá encaminhar a solicitação a uma classe especializada. É aí que entra o padrão command. Quem não se lembra das famosas Actions do struts? Isso é o padrão command. Vamos implementar:

Crie uma interface Command

public inerface Command{
   public void execute(HttpServletRequest request, HttpServletResponse response);
}

Agora crie um pacote chamado 'commands' que irá conter seus commands.

Em seguida, vamos criar nossas implementações de Command:

package commands;
//imports
public class AlterarProduto implements Command{
   public String execute(HttpServletRequest request, HttpServletResponse response){
      //ALTERA O PRODUTO      
   }
}

package commands;
//imports
public class DeletarProduto implements Command{
   public String execute(HttpServletRequest request, HttpServletResponse response){
      //DELETA O PRODUTO      
   }
}

Agora vamos alterar o nosso Controller para reconhecer esses commands. Ele deve ser acessado pela seguinte url: Controller?command=AlterarProduto ou Controller?command=DeletarProduto. O parametro command é o nome da classe dos commands que implementamos. Se for necessário incluir um terceiro command 'CadastrarProduto' basta passar o nome nesse parametro e criar a classe que implementa Command no pacote commands.

Segue o controller

package servlets;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class Controller extends HttpServlet {
    
    protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //VERIFICA SE O USUARIO ESTÁ LOGADO
        //REGISTRA LOG DE ACESSO

        //EXECUTA O COMANDO ESPECIFICADO NA URL
        Command comando = (Command)Class.forName("commands."+request.getParameter("command")).newInstance();
        comando.execute();        
    }
    
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }
   
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }
   
    @Override
    public String getServletInfo() {
        return "Short description";
    }
}

Percebam que na instanciação do command e passo o nome da classe informada pela url. Aqui podemos visualizar o motivo do padrão command facilitar a padronização. Visto que todos os commands implementam a interface Command podemos usar o polimorfismo e instanciar várias implementações diferentes. Isso permite que nossa aplicação cresça sem a necessidade de alterar o nosso controller ou o nosso web.xml por adicionar novos servlets.

O foco deste artigo foi explicar e demonstrar os padrões front controller e command. Naturalente existem maneiras mais bem elaboradas para implementar, usando por exemplo DI e annotations. Porém desta maneira os conceitos são apresentados sem perder o foco.

Num próximo artigo apresentarei os padrões front controller e command implementados em PHP.

Atenciosamente,
Gustavo Marques

Nenhum comentário:

Postar um comentário

Veja também

Related Posts Plugin for WordPress, Blogger...