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.
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.
Gustavo Marques
Nenhum comentário:
Postar um comentário