Beruflich Dokumente
Kultur Dokumente
Precisamos de um exemplo único e simples, que seja suficientemente complexo para demonstrar
o desenvolvimento de uma aplicação Java por meio do padrão de projeto de software Model-
View-Controler (MVC). Maiores informações sobre MVC em
http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller. Vamos usar a
calculadora como exemplo. Nossa calculadora efetuará operações de soma, subtração, divisão e
multiplicação.
Nas entrevistas com o usuário conseguimos compreender que o mesmo almeja uma calculadora
simples, que efetue as operações básicas e que permita inserir n operandos e não somente dois
operandos, como são comuns nas calculadoras convencionais. Neste sentido, nossa calculadora
efetuará somas, divisões, subtrações e multiplicações de n números, sejam reais ou inteiros. O
usuário poderá listar quais foram as operações realizadas na calculadora desde sempre!
Após identificar os requisitos, a primeira pergunta que devemos fazer como programador é: Como
o usuário deverá usar a calculadora? Certamente da forma mais simples e intuitiva possível. Neste
sentido, iremos inicialmente modelar a View (o V do MVC). Iremos usar uma interface gráfica do
tipo desktop, porém graças ao nosso projeto MVC não iremos ter muitas recodificações se
almejarmos trocar nossa calculadora por uma interface gráfica Web ou mesmo Android.
Como iremos usar o Java, precisamos de uma IDE para Java. Neste tutorial iremos usar o Eclipse
como IDE Java. Para o desenvolvimento dos componentes gráficos como botões, caixas de texto,
rótulos, botões de rádio, entre outros, iremos usar o WindowBuilderPro. Trata-se de uma solução
Google para rápida prototipação de interfaces gráficas Java Swing. O WindowBuilderPro funciona
como um plugin Eclipse. Faça o download do WindowBuilderPro, siga as recomendações do site,
reinicie o Eclipse e vamos a construção do V do MVC. De uma forma geral, nesta parte do tutorial
iremos entender a necessidade do usuário, podendo assim apresenta-la graficamente e
efetivamente funcionando. Com isto, conseguiremos prototipar telas até que o usuário aprove.
Uma vez criado o projeto, iremos criar a classe Java responsável pela interface gráfica. Interfaces
gráficas sofisticadas requerem n classes similares a que iremos fazer neste tutorial. Para isto, basta
clicar no pacote view com o botão direito do mouse e depois no menu new => other. Daí basta
escolher uma nova classe jgoodies, conforme ilustra a Figura 2. Note que no Eclipse o JGoodies
aparece como WindowBuilder.
Figura 2. Classe View com o JGoodies
Iremos escolher um JFrame como componente principal de nossa interface gráfica. Note que é
possível construir applets web e diversas outras interfaces, algumas sendo internas a sua aplicação
como é o caso do JInternalFrame. A nova classe chama GUI_calculadora, conforme ilustra a Figura
3. Para que você consiga programar visualmente sua classe com o JGoodies, basta clicar na aba
design. Em suma, ao clicar em design o JGoodies lhe provê programar visualmente a classe
GUI_calculadora. Na Figura 4 ilustramos o painel da aplicação calculadora, assim como os
inúmeros componentes Java Swing disponíveis para que possamos construir interfaces gráficas
para nossos softwares com tecnologia Java.
Figura 3. Classe GUI_calculadora, gerada a partir do JGoodies
A primeira tarefa é inserir um layout que mantenha os componentes visuais de sua tela ajustados
e formatados adequadamente. Neste tutorial escolhemos o FormLayout. Basta selecionar o
FormLayout e o arrastar para a interface gráfica em construção. O resultado é ilustrado na Figura
5. Com o FormLayout temos uma matriz onde podemos inserir os componentes e os ajustar
dentro de uma célula de tal matriz de componentes Swing. Notem que é possível desenvolver
interfaces gráficas extremamente sofisticadas com o JGoodies como plugin Eclipse.
Figura 5. Usando o FormLayout para garantir formatação e ajustamento nos componentes da tela
Após definir o layout, passamos a definir os componentes que o usuário irá interagir. Perceba a
importância desta fase de desenvolvimento de software, pois é nela que nos colocamos como
usuários do sistema, definindo para isto o conjunto de eventos e componentes visuais que tornem
a aplicação simples e que resolva o problema definido pelo usuário. No nosso caso trata-se de uma
calculadora que efetue as operações básicas sobre n operandos, sejam eles reais ou inteiros. Na
Figura 6 ilustramos como ficará a interface gráfica da calculadora. Usamos para isto alguns
JTextFields para permitir que o usuário insira textos, JComboBox para que o usuário informe qual
operação almeja executar, um botão que inicia o cálculo, um botão que lista os cálculos já
realizados e uma JTextArea para exibir tal listagem. Note que podemos programar em JGoodies
outras inúmeras maneiras de atender os requisitos do usuário, portanto nossa solução é apenas
uma das alternativa que atende aos requisitos e que busca SEMPRE A SIMPLICIDADE E A
USABILIDADE. Assumimos daqui para frente que o usuário aprovou a GUI ilustrada na Figura 6.
Agora é desenvolver o M e o C do MVC!
Figura 6. Proposta de interface gráfica para calculadora.
Uma vez que usuário concordou com as interfaces gráficas desenvolvidas rapidamente com o
JGoodies, passamos a implementar também visualmente os eventos necessários. Nesta etapa
iniciamos o desenvolvimento do M (model) do MVC. Na Figura 7 ilustramos a adição do evento
mouseClicked à partir de um simples clique com o botão direito do mouse no componente que
você almeja adicionar o evento (no nosso caso o botão com label Executar), em seguida add event,
em seguida mouse e por fim mouse clicked. O resultado é apresentado na forma de código, como
ilustra a Figura 8.
Figura 7. Inserção de forma visual de eventos a componentes Java Swing
Quando o usuário clica no botão executar o código da Figura 8 é executado, portanto podemos
assumir que uma operação da calculadora será solicitada. Neste sentido, definimos parte do
modelo (M do MVC), pois de alguma forma nossa solução deverá controlar uma operação,
provendo o cálculo da mesma. Neste tutorial a classe operação deverá possuir os atributos: (i)
operandos como uma lista de números, (ii) o operador e (iii) o resultado. Outro requisito a ser
atendido é listar os cálculos já realizados. Para atendê-lo inserimos a classe calculadora. Uma
calculadora possui um conjunto de operações já realizadas. Nossa classe calculadora possui: (i) um
identificador e (ii) uma lista de operações. O projeto já possui seu modelo, composto pelas classes
Operação e Calculadora, conforme ilustra a Figura 9. O modelo pode possuir "v" Views e "c"
Controllers. Esta é a grande vantagem do MVC. Iremos apresentar a calculadora em GUIs desktop,
web e Android. Além disto, iremos efetuar o controle local e distribuído, mostrando com isto que
o projeto MVC_Java possui fraco acoplamento entre seus módulos e consequentemente alta
flexibilidade. O controle de uma simples calculadora se resume a alguns filtros e as operações
básicas. Por outro lado, alguns controles podem exigir lógicas complexas, elevado número de
componentes, assim como alta dependabilidade entre os componentes. Nestes cenários, o
número de classes de controle aumenta, ser escalável se torna árduo e ter manutenibilidade é
praticamente um pesadelo!
Já sabemos que deveremos ter as classes Operacao e Calculadora. Já temos ideia de quais são os
atributos de cada classe, assim como os requisitos da calculadora. Então, já podemos construir
diagrama de classes UML para o modelo de nosso aplicativo. Assim, permitimos que o projeto
Java_MVC possa ser conduzido em equipe, facilitando a comunicação de sua estrutura e
aumentando significativamente seu tempo de vida. A Figura 9 ilustra um diagrama de classes para
o modelo de nosso projeto Java. Usamos o produto Gliffy, pois é online, gratuito em algumas
licenças e possui um enorme catálogo de diagramas, incluindo UML, ER. Basta criar uma conta em
http://www.gliffy.com e começar a usar!
Temos as classes Operacao, Calculadora e a superclasse Model. A superclasse Model é uma boa
pratica de projeto. É comum as classes do modelo terem que ser persistidas em disco ou em um
banco de dados relacional (Oracle, SQL Server, MySQL ou PosGreSQL). Outra necessidade comum
nos projetos é termos que transferir classes (objetos no caso!!!) do modelo pela rede. Diante da
justificativa exposta, adicionamos a superclasse Model que todas as demais classes do modelo
devem herdar. A classe Model possui um identificador e estende as interfaces Java Serializable,
Cloneable e Comparable. A Figura 10 ilustra a classe Model de nosso projeto Java e suas relações.
Com esta simples atitude conseguimos implementar um modelo que pode ser persistido e enviado
pela rede. A outra opção seria colocar implements Serializable, Comparable, Cloneable para cada
classe de seu modelo. Iremos EVITAR esta opção por ser suscetível a erros da equipe de
programação. É obrigatório as classes do Modelo (M do MVC) implementarem os métodos equals,
compareTo, clone e hashCode. Desta forma estaremos implementando um modelo robusto! Mais
a frente voltaremos a este assunto.
Note que as variáveis de cada classe devem ser privadas, conforme ilustra a Figura 11. A Figura 12
ilustra como gerar os métodos get e set para todas ou algumas variáveis globais. Não há
necessidade de gerar os métodos get e set para cada variável. Ao invés disto, basta clicar com o
botão direito em qualquer ponto da área onde você programa no Eclipse e escolher a opção
generate getters and setters.
Após geração, verifique o JavaDoc gerado no seu navegador preferido. O resultado deve ser
similar ao ilustrado na Figura 16 para classe Operacao.
Figura 14. Javadoc criado para o projeto MVC_Java
Para fecharmos as tarefas com a classe Operacao devemos construir a classe que testará se
Operacao funciona adequadamente, isto é, o teste unitário para a classe Operacao. Iremos usar o
JUnit para realizar os testes unitários do projeto MVC_Java.
À medida que o projeto avança, o mesmo procedimento adotado para a classe Operacao deverá
ser realizado para demais classes do projeto MVC_Java (todos os pacotes M, V e C), ou seja: (i)
concepção, (ii) modelagem UML, (iii) implementação da classe, (iv) documentação javadoc, (v)
geração do javadoc e (vi) teste. Gostaríamos de destacar a importância dos TESTES por serem
frequentemente desconsiderados nos projetos devido aos prazos, porém não realiza-los pode sair
muito mais caro.
O plugin JUnit já se encontra instalado em sua IDE Eclipse (versão 3.7), portanto basta clicar com o
botão direito em cima da classe Operacao e selecionar JUnit, depois JUnit Test Case. A Figura 15
ilustra a GUI Eclipse para este passo.
Após a criação da classe OperacaoTest percebemos que há um método de teste para cada método
publico de Operacao (getters e setters). Na Figura 16 ilustramos os métodos de teste para os
métodos públicos getOperador e setOperador da classe Operacao. A regra de preenchimento não
é complexa se feita desde o início do projeto. Em todos os métodos da classe de testes unitários,
um objeto da classe Operacao é criado e a partir daí efetuamos dois testes: se o operador não for
atribuído deve retornar null e se o operador se chamar teste retorne teste. No caso do método
setOperador o teste se resume a verificar inserções positivas ou negativas. O método assertEquals
exige uma String como mensagem, o resultado esperado e o objeto a ser testado. Simples e
robusto. Maiores informações sobre JUnit em: http://www.junit.org/.
Figura 15. Explorer Eclipse para criação de classes de testes unitários
Figura 16. Métodos de teste da classe Operacao, mais precisamente os métodos get/set operador
Mais a frente ensinaremos como criar suítes de teste, ou seja, a execução de inúmeras classes de
teste. Por agora para testar Operacao basta clicar com o botão direito do mouse na classe
OperacaoTest, em seguida run as, depois em JUnit Test. A Figura 17 ilustra este passo. A Figura 18
ilustra o resultado da execução da classe OperacaoTest. Notem na Figura 18 que não existem erros
segundo os testes feitos na classe Operacao. Conduza sempre testes com resultados nulos, para
resultados numéricos sempre use negativo, zero e algum positivo, seja real ou inteiro. Nunca
passe para a próxima classe sem antes conduzir testes unitários com êxito.
Até o momento ainda não concebemos como iremos resolver os eventos executar operação e
listar operações realizadas. O que fizemos até agora foi implementar as classes do model
responsáveis por armazenar os dados necessários ao projeto MVC_Java. A partir de agora
dedicaremos as classes Controllers, responsáveis pela lógica ou controle do projeto sendo
desenvolvido. Note que projetos com uma lógica complexa ou projetos extensos irão requerer n
classes Controllers, uma para cada ação ou requisito da aplicação.
No nosso exemplo temos como requisito prover o cálculo de uma operação e listar os cálculos já
realizados. Iremos implementar duas classes Controller para este fim. A primeira se chamara
ControladorOperacao e a segunda ControladorCalculadora. Na Figura 19 ilustramos o diagrama de
classes completo do projeto MVC_Java, no qual é possível verificar a presença das classes dos
pacotes View, Model e Controller.
Figura 19. Diagrama de classes do projeto MVC_Java
Note na Figura 22 a presença da instrução Java try. Trata-se de mais uma fundamental informação
deste projeto. Sempre use as cláusulas try e catch para TODOS os métodos de suas classes do
controle. Tais cláusulas adicionam robustez ao seu código, pois adicionam execuções extras no
caso de qualquer erro no bloco principal. No bloco de código secundário, chamado catch, você
sempre possui a chance de arquivar o erro em logs, chamar nova computação com novos
argumentos, entre outras possibilidades.
A classe GUI ou View de nosso projeto é a nossa próxima observação. Na classe GUI_Calculadora,
quando o usuário clica em calcular, uma operação é criada sem o resultado e submetida ao
controle ControladorOperacao para que o mesmo proceda o cálculo. O resultado da operação é
exibido na GUI. O evento listar operações acontece de maneira similar ao explicado
anteriormente. Maiores informações no projeto Java que acompanha este tutorial. Na Figura 23
temos o trecho de código que submete o cálculo de uma nova operação na calculadora.
Até o momento temos o MVC implementado e o nosso projeto plenamente funcional, porém
ainda falta explicar o motivo da classe ControladorPersistencia. Entramos finalmente na reta final
deste primeiro tutorial.
A interface ControladorPersistencia é ilustrada na Figura 25. Esta interface possui apenas dois
métodos (salvar e retornar) e permite inúmeras implementações. Neste primeiro tutorial iremos
implementar apenas a persistência como OBJETO SERIALIZADO no sistema de arquivos do seu
Sistema Operacional. A classe calculadora e o que calculadora possui (Operacao, por exemplo)
podem ser serializados facilmente, pois ou são tipos primitivos ou implementam Java Serializable
interface.
Figura 25. Interface ControloadorPesistencia
A implementação realizada neste primeiro tutorial é ilustrada nas Figuras 26 e 27. A classe
ControladorPersistenciaImpl usa as classes de I/O Java chamadas FileOutputStream e
FileInputStream. Tais classes permitem que objetos java sejam convertidos em arquivos binários e
salvos em disco facilmente. Buffers são usados e encapsulam a leitores de arquivos, permitindo
que a instrução oos.writeObject(calc); seja otimizada. Java permite um reuso absurdo quando o
assunto é I/O. Seu desenho permite o programador trocar facilmente leituras ou gravações de
arquivos, por leituras ou envios via socket (TCP) ou datagrama (UDP). Maiores detalhes sobre I/O
em Java no link http://docs.oracle.com/javase/tutorial/essential/io/. No próximo tutorial iremos
implementar a possibilidade de salvar Calculadora num banco de dados relacional (Oracle, MySQL
ou qualquer outro) e também a armazenar calculadora num cluster de PCs, usando para isto o
middleware JavaCá&Lá, projeto coordenado pelo prof. Joubert e distribuído gratuitamente no link
www.joubertlima.com.br/calapp.
Figura 26. Implementação da classe ControladorPersistencia para salvar objetos Java em disco
Figura 27. Implementação da classe ControladorPersistencia para recuperar objetos Java em disco
O arquivo calc1 criado em disco é ilustrado na Figura 29. O arquivo é a versão de Calculadora com
suas n operações armazenadas. Desta forma, podemos inicializar quantas vezes quisermos a
aplicação calculadora e NENHUMA OPERAÇÃO SE APAGARÁ, pois estão sempre armazenadas em
disco. Para inicializarmos a calculadora basta apagarmos o arquivo calc1 do diretório.
Figura 29. Arquivo calc1 gerado para persistir a calculadora e suas operações
Por fim, iremos criar um suíte de testes, facilitando desta forma a execução de testes em mais de
uma classe. Durante o ciclo de vida do projeto o suíte de testes deverá ser executado inúmeras
vezes. Qualquer nova implementação deverá ser acompanhada de um novo teste, porém não o
unitário e sim o suíte inteiro. Na Figura 30 ilustramos como criar um suíte de teste com o JUnit.