Java para Web
231 pág.

Java para Web


DisciplinaOrientação A Objetos170 materiais1.087 seguidores
Pré-visualização45 páginas
para apenas oito linhas: colocar tudo numa Servlet
só, e de acordo com que argumentos o cliente nos passa, decidimos o que executar. Teríamos aí uma Servlet
monstro.
public class TesteServlet extends HttpServlet{
protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String businessLogic = request.getParameter("business");
ContatoDAO dao;
try {
dao = new ContatoDAO();
if(businessLogic.equals("AdicionaContato")) {
Contato contato = new Contato();
contato.setNome(request.getParameter("nome"));
Capítulo 12 - Model View Controller - Melhorando o processo - Página 105
Material do Treinamento Java para Desenvolvimento Web
contato.setEndereco(request.getParameter("endereco"));
contato.setEmail(request.getParameter("email"));
dao.adiciona(contato);
} else if (businessLogic.equals("ListaContato")) {
// algo como dao.lista();
}
} catch (SQLException e) {
throw new ServletException(e);
}
}
}
Para cada ação teríamos um if / else if, ficaria gigante, não?
Podemos melhorar fazendo refactoring de extrair métodos. Mas continuaria gigante.
Seria melhor colocar cada regra de negócio (como inserir aluno, remover aluno, fazer relatório de um aluno,
etc...) em uma classe separada. Cada ação (regra de negócio) em nossa aplicação estaria em uma classe.
Então vamos extrair classes:
if (businessLogic.equals("AdicionaContato")) {
new AdicionaContato().execute(request,response);
} else if (businessLogic.equals( "ListaContato")) {
new ListaContatos().execute(request,response);
}
Porém, a cada lógica nova, lógica removida, alteração etc, temos que alterar essa servlet. Isso é trabalhoso
e muito propenso a erros humanos.
Repare que o código acima é um switch! E switch em Java é tão ruim que substituímos por polimorfismo,
como veremos a seguir.
Vamos tentar generalizar então, queremos executar o seguinte código:
String business = request.getParameter("business");
new business().execute(request,response);
Entretanto não podemos, pois business é o nome de uma variável. O nosso problema é que só sabemos o
que vamos instanciar em tempo de execução e não em tempo de compilação.
Temos como fazer isso? Sim.
String businessLogicClassName = "br.com.caelum.mvc." + request.getParameter("business");
Class businessLogicClass = Class.forName(businessLogicClassName);
Mas e agora como instanciar essa classe?
Object obj = businessLogicClass.newInstance();
E como chamar o método execute? Repare que usamos o mesmo método em todas as lógicas de negócio:
isso é um padrão que definimos. Quando isso aparece, é normal extrair uma interface comum a todas essas
classes: BusinessLogic.
Capítulo 12 - Model View Controller - Melhorando o processo - Página 106
Material do Treinamento Java para Desenvolvimento Web
BusinessLogic businessLogicObject = (BusinessLogic)businessLogicClass.newInstance();
businessLogicObject.execute(request, response);
Alguém precisa controlar então que ação será executada para cada requisição, e que JSP será utilizado. Po-
demos usar uma servlet para isso, e então ela passa a ser a servlet controladora da nossa aplicação, chamando
a ação correta e fazendo o dispatch para o JSP desejado.
Repare na figura a seguir que, apesar dos JSPs não estarem acessando a parte da sua modelagem, isto é,
as classes que direta ou indiretamente mexem no banco de dados, ele tem uma referência a um usuário, para
poder colocar suas informações na página resultante. Chamamos isso de \u201cpush\u201d das informações.
12.5 - Retomando o design pattern Factory
Note que o método forName da classe Class retorna um objeto do tipo Class, mas esse objeto é novo? Foi
reciclado através de um cache desses objetos?
Repare que não sabemos o que acontece exatamente dentro do método forName, mas ao invocá-lo e a
execução ocorrer com sucesso, sabemos que a classe que foi passada em forma de String foi lida e inicializada
dentro da virtual machine.
Na primeira chamada a Class.forName para determinada classe, ela é inicializada. Já em uma chamada
posterior, Class.forName devolve a classe que já foi lida e está na memória, tudo isso sem que afete o nosso
código.
Esse exemplo do Class.forName é ótimo para mostrar que qualquer coisa que isola a instanciação através
de algum recurso diferente do construtor é uma factory.
Capítulo 12 - Model View Controller - Retomando o design pattern Factory - Página 107
CAPÍTULO 13
Construindo um Framework MVC
\u201cHá duas tragédias na vida. Uma é a de não obter tudo o que se deseja ardentemente; a outra, a de obtê-lo.\u201d
\u2013 Bernard Shaw
Não existe mistério por trás de um framework MVC. Vamos criar aqui o SYP MVC Framework \u2013 Simple Yet
Porwerful MVC Framework.
13.1 - Nossa interface de execução
Para o nosso pattern de comando, que todas as lógicas irão seguir, definiremos a seguinte interface de
execução:
public interface BusinessLogic {
void execute(HttpServletRequest req, HttpServletResponse res) throws Exception;
}
Parece uma servlet certo? A primeira vista sim, mas perceba que não tem nada com uma servlet. Estende
Servlet? Possui método chamado service? Não.
Vamos criar uma lógica de negócio de exemplo para testá-la em breve:
public class TestaMVC implements BusinessLogic {
public void execute(HttpServletRequest req, HttpServletResponse res)
throws Exception {
System.out.println("Executando a logica e redirecionando...");
RequestDispatcher rd = req.getRequestDispatcher("/testa-mvc.jsp");
rd.forward(req, res);
}
}
13.2 - Exercícios
1) Crie a sua interface no pacote br.com.caelum.mvc:
package br.com.caelum.mvc;
public interface BusinessLogic {
void execute(HttpServletRequest req, HttpServletResponse res) throws Exception;
}
108
Material do Treinamento Java para Desenvolvimento Web
2) Crie uma implementação da interface BusinessLogic, nossa classe TestaMVC, no mesmo pacote:
package br.com.caelum.mvc;
public class TestaMVC implements BusinessLogic {
public void execute(HttpServletRequest req, HttpServletResponse res) throws Exception {
System.out.println("Executando a logica e redirecionando...");
RequestDispatcher rd = req.getRequestDispatcher("/mvc-ok.jsp");
rd.forward(req, res);
}
}
13.3 - Criando um controlador e um pouco mais de reflection
Nosso objetivo é que o nome da classe que implementa a interface BusinessLogic seja passada como
parâmetro por HTTP. Esse argumento será o business. Nossa servlet controladora é responsável por instanciar
essa classe e chamar o seu método execute.
Vamos começar com a declaração da servlet e pegar o nome da classe como parâmetro:
public class ControllerServlet extends HttpServlet {
protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String business = request.getParameter("business");
String className = "br.com.caelum.mvc." + business;
Nesse momento, temos o nome da classe que precisamos instanciar.
Quando vimos JDBC aprendemos que a classe Class possui um método estático chamado forName que
carrega uma determinada classe. Além de carregar a classe, o forName devolve uma referência a um objeto do
tipo Class que representa aquela classe. É isso que faremos:
Class clazz;
try {
clazz = Class.forName(className);
} catch (ClassNotFoundException e) {
throw new ServletException("Não encontro a classe " + className);
}
Essa String className deve ser precedida do nome do pacote ao qual essa classe pertence, como
\u201cbr.com.caelum.mvc.AdicionaContato\u201d por exemplo. Caso a classe não for encontrada, uma exceção
ClassNotFoundException é disparada.
Um objeto do tipo Class possui um método newInstance, que tenta instanciar um objeto daquele tipo usando
o construtor público que não recebe nenhum argumento da classe. Caso o construtor não exista, não seja
público, ou lance uma Exception, uma exceção