Anda di halaman 1dari 32

Assine agora e tenha acesso a

todo o contedo da DevMedia:


www.devmedia.com.br/mvp

Edio 56 2015 ISSN 2173625-4

Fale com o Editor!


Atendimento ao leitor
EXPEDIENTE A DevMedia possui uma Central de Atendimento on-line, onde voc muito importante para a equipe saber o que voc est achando da revista:
que tipo de artigo voc gostaria de ler, que artigo voc mais gostou e qual
pode tirar suas dvidas sobre servios, enviar crticas e sugestes e
artigo voc menos gostou. Fique a vontade para entrar em contato com os
falar com um de nossos atendentes. Atravs da nossa central tambm editores e dar a sua sugesto!
Editor possvel alterar dados cadastrais, consultar o status de assinaturas Se voc estiver interessado em publicar um artigo na revista ou no site
e conferir a data de envio de suas revistas. Acesse www.devmedia. Easy Java Magazine, entre em contato com o editor, informando o ttulo e
Eduardo Spnola (eduspinola@gmail.com)
com.br/central, ou se preferir entre em contato conosco atravs do mini-resumo do tema que voc gostaria de publicar:
telefone 21 3382-5038.
Consultor Tcnico Diogo Souza (diogosouzac@gmail.com)
Publicidade
publicidade@devmedia.com.br 21 3382-5038 Eduardo Oliveira Spnola
Produo
eduspinola.wordpress.com
Jornalista Responsvel Kaline Dolabella - JP24185 Anncios Anunciando nas publicaes e nos sites do Grupo DevMedia,
voc divulga sua marca ou produto para mais de 100 mil desenvolvedores @eduspinola / @Java_Magazine
Capa e Diagramao Romulo Araujo de todo o Brasil, em mais de 200 cidades. Solicite nossos Media Kits, com
detalhes sobre preos e formatos de anncios.

Sumrio
Contedo sobre Boas Prticas, Artigo no estilo Soluo Completa

04 - UML e Java na prtica


[ John Soldera ]

Contedo sobre Boas Prticas, Artigo no estilo Soluo Completa

13 - Refatorando cdigo com padres de projeto


[ Gabriel Feitosa ]

Contedo sobre Boas Prticas, Artigo no estilo Soluo Completa

21 - Aprenda a utilizar o Spring Web Flow


[ Alessandro Jatob ]
UML e Java na prtica

UML e Java na prtica


Aprenda nesse artigo o que UML e como
desenvolver uma aplicao simples a partir dos
diagramas de casos de uso e de classes

A Fique por dentro


linguagem de modelagem UML (Unified Mode-
ling Language) uma das linguagens de mode-
lagem de software mais utilizadas no mundo. Atravs de exemplos este artigo abordar como converter alguns
Como um dos seus diferenciais, oferece um conjunto de dos principais diagramas da linguagem de modelagem UML, obtidos
diagramas padronizados para modelar as mais variadas durante o projeto de software, em cdigo Java. Ao longo desse es-
caractersticas dos sistemas de informao, como o dia- tudo ser analisada a documentao em UML de uma aplicao de
grama de casos de uso, diagrama de classes, diagrama controle de estoque, mais especificamente os diagramas de casos de
de sequncia, entre outros. uso e de classes, e os mesmos sero convertidos, passo a passo, para
Atravs do diagrama de casos de uso possvel mo- a criao de classes, atributos e mtodos. O conhecimento sobre estes
delar as funcionalidades que o sistema fornecer ao conceitos algo fundamental caixa de ferramentas de todo desen-
usurio; com o diagrama de classes, pode-se definir as volvedor que tem como meta cdigos mais fceis de compreender,
entidades e seus relacionamentos; e atravs do diagrama evoluir e manter.
de sequncia, conseguimos informar a ordem em que
os objetos se comunicam para realizar as operaes
descritas nos casos de uso. A linguagem UML tambm atua na etapa de projeto do software,
Pelo fato da linguagem Java ser orientada a objetos, a momento em que so definidos a arquitetura do sistema, a lingua-
converso dos diagramas da UML para cdigo-fonte gem de programao utilizada, o banco de dados, a tecnologia de
simples e direta. Alm disso, essa linguagem apresenta interface grfica e a adoo de padres de projeto. Em seguida,
uma sintaxe simplificada quando comparada com outras na fase de implementao, o projeto de software interpretado
opes, o que facilita o processo de desenvolvimento e transformado em cdigo na linguagem escolhida usando os
de software. padres especificados. Por ltimo, ocorre a fase de teste, onde
Dito isso, com o intuito de ilustrar o processo de co- cada funcionalidade do sistema testada. Saiba que a fase de teste
dificao a partir de diagramas UML, uma aplicao pode ser executada desde o incio do projeto, atravs da criao
bsica de controle de estoque ser desenvolvida de de casos de testes integrados ao cdigo-fonte, com o auxlio de
forma que o cdigo-fonte seja organizado em camadas, ferramentas como o JUnit.
soluo adotada para a construo da maioria dos Com base no contedo exposto, a seguir ser apresentado o
sistemas hoje em dia. Lembre-se que uma abordagem desenvolvimento de uma aplicao exemplo a partir de alguns
simplificada para organizar o cdigo-fonte de um diagramas da linguagem UML, artefatos estes que visam espe-
programa dividir a aplicao em trs nveis: camada cificar caractersticas importantes do software durante a fase de
de apresentao, camada de negcios e camada de anlise.
dados.
Como ocorre normalmente em qualquer projeto de Aplicao exemplo
software, o ciclo de desenvolvimento envolve quatro A aplicao exemplo desse artigo tem o objetivo de realizar o
grandes etapas: anlise, projeto, implementao e testes. controle de estoque de um supermercado. Com isso em mente,
Tidas como fundamentais, pular uma dessas etapas vamos modelar esta soluo utilizando dois dos diagramas mais
pode acarretar imprecises, retrabalho e prejudicar conhecidos da UML, o diagrama de casos de uso e o diagrama
diretamente a qualidade do produto. de classes. Atravs deles possvel especificar o que usurio
durante a anlise que o analista investiga e descobre pode fazer no sistema, bem como as entidades do contexto do
como funciona o sistema em questo. nessa fase que o problema; neste caso, fornecedores, produtos, unidades de medida
problema do mundo real estudado e a soluo proposta e pedidos. Porm, para no tornar o artigo muito longo, vamos
descrita atravs de modelos que sejam capazes de guiar focar apenas na implementao de algumas funcionalidades:
o projeto do software. o cadastro de fornecedores, unidades, produtos e pedidos.

4 Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia


Espera-se que com o contedo o exposto o leitor consiga desen-
volver as demais opes.

Casos de Uso
Este diagrama descreve o que o usurio pode fazer. Como exem-
plo, vejamos, na Figura 1, o primeiro caso de uso da aplicao em
desenvolvimento: Cadastro de Fornecedor.
Note que o usurio deve ter acesso a quatro funcionalidades
relacionadas entidade Fornecedor: criao, edio, excluso e
listagem.
A Figura 2 apresenta outro caso de uso, de nome Cadastro de
Unidade. Nele, de modo semelhante ao exemplo anterior, so
descritas as iteraes que o usurio do sistema ter com a enti- Figura 1. Caso de Uso Cadastro de Fornecedor
dade unidade. Assim, deve ser possvel criar, editar, excluir e
consultar unidades de medida, que sero usadas no cadastro de
produtos como ser mostrado mais frente.
Encerrando a modelagem dos casos de uso, especificamos ainda
os diagramas Cadastro de Produto e Cadastro de Pedido (vide
Figuras 3 e 4), que, como verificado, seguem a mesma tendncia
apresentada pelos outros exemplos.
Note que atravs dos casos de uso j estabelecemos uma diviso
para o sistema, de forma que o usurio possa modificar cada parte
do sistema separadamente. Com o auxlio destes, os diagramas
subsequentes na anlise consideram as informaes levantadas e
modelam outras caractersticas, como veremos a seguir.
Figura 2. Caso de Uso Cadastro de Unidade
Diagrama de Classes
atravs da criao de classes que a informao gerenciada pelo
sistema organizada em entidades separadas. Sabendo disso, para
que o software tenha um cdigo com boa legibilidade e fcil manu-
teno, cada entidade deve conter apenas os atributos e mtodos a
ela relacionados. A partir disso, para estabelecer o funcionamento
do sistema e tambm para compor entidades mais complexas, so
definidos os relacionamentos entre essas classes.
O diagrama de classes se encaixa exatamente nesse contexto e
nada mais do que uma forma de representar as classes/interfa-
ces, atributos, mtodos e relacionamentos de um sistema de forma
visual. A partir dele o desenvolvedor ter um mapa do que
implementar, o que facilita o trabalho de implementao e reduz
o risco de criar cdigos desnecessrios. A Figura 5 apresenta o Figura 3. Caso de Uso Cadastro de Produto
diagrama de classes da aplicao exemplo.
Note que organizamos os dados da aplicao em cinco entidades:
Fornecedor, Unidade, Pedido, ItemPedido e Produto. Alm disso,
especificamos seus atributos, mtodos e relacionamentos.
Ao analisar a entidade Fornecedor, por exemplo, verificamos
que ele tem os atributos codigoFornecedor, endereo, telefone e
nome. Como mtodos, foram especificados o criarFornecedor(),
editarFornecedor(), excluirFornecedor(), consultarFornecedor()
e consultarFornecedores(). Ademais, note que ele se relacionada
com a entidade Pedido. Com esta ligao estamos indicando que
um fornecedor pode ter zero ou muitos pedidos. Esta mesma lgi-
ca se aplica s demais entidades, respeitando sempre as diferenas
de cada tipo de relacionamento. Figura 4. Caso de Uso Cadastro de Pedidos

Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia 5


UML e Java na prtica

Fase de Projeto de Software dados, e uma classe DTO, que contm os atributos de cada entidade.
Concluda a fase de anlise, deve-se prosseguir para a fase de Em definio simples, um objeto DTO representa um objeto de
projeto de software, onde os diagramas obtidos anteriormente dados que pode ser enviado entre camadas distintas do software.
so convertidos em documentos ou outros diagramas de forma
que seja mais fcil ao programador se basear neles para realizar Criao do Banco de Dados
o desenvolvimento do software. Durante a fase de projeto so Uma vez que se tenha evoludo na especificao do diagrama
produzidos documentos e diagramas semelhantes aos da fase de classes da fase de projeto, pode-se partir para a criao das
de anlise, porm tal informao sofre um detalhamento maior tabelas no banco de dados, elementos que sero responsveis
e os processos so expandidos, muitas vezes empregando-se de pela persistncia dos objetos que forem criados durante o ciclo
pseudocdigo para descrever procedimentos. de vida do software.
Alm disso, na fase de projeto que so especificados os design Em muitos projetos, uma das primeiras coisas a serem defini-
patterns para facilitar e organizar a implementao do software, das o banco de dados. Nestes casos, comumente, um modelo
pois existe uma tendncia das classes originais conterem muita ER (Entidade Relacionamento) pode ser a nica documentao
informao pertencente a diferentes camadas da aplicao, o disponvel no sistema. Entretanto, essa estratgia no adequada,
que causa uma forte vinculao entre essas camadas e prejudica uma vez que antecipa e distorce o processo de desenvolvimento
diretamente a manuteno e legibilidade do cdigo. de software, alm de centralizar todo o conhecimento do sistema
Hoje j existem diversas formas de se organizar um software sobre as poucas pessoas envolvidas no processo de anlise.
em camadas. Dentre elas, uma das mais conhecidas o padro Outro aspecto importante em um projeto de software eficiente
Model-View-Controller, que amplamente empregado em Java para e robusto criar no banco de dados todas as verificaes neces-
organizar o software em camada de apresentao, de modelo e srias sobre os dados para evitar o estado inconsistente da base,
de controle. o que pode acontecer devido ao mau uso do sistema por parte do
Alm deste, outro padro bastante adotado o Data Access Ob- usurio ou em decorrncia de falhas no software, como bugs ou
ject, opo que leva a uma diviso das classes em uma estrutura falta de validaes de dados de formulrios.
que abstrai e reduz o acoplamento do cdigo com as tecnologias Portanto, importante criar corretamente as chaves primrias,
utilizadas para acesso a dados. chaves estrangeiras e chaves nicas (campos que no se repetem)
Em nosso exemplo, cada classe presente na Figura 5 ser refato- a fim de barrar na camada de persistncia a repercusso de even-
rada em duas: uma classe DAO, que contm os mtodos de acesso a tuais falhas que possam ocorrer nas outras camadas.

Figura 5. Diagrama de Classes

6 Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia


Como parte da fase de projeto, os analistas geram a especificao Como visto nesse cdigo, o nome da base de dados exemplo ser
de cada tabela e de cada campo do banco de dados informando o Estoque. Observe tambm que foram definidos os tamanhos
tipo e o tamanho do mesmo. Alm disso, ele mesmo pode criar a dos campos e seus tipos usando os tipos de dados disponveis
base de dados se tiver conhecimento na rea (e se a empresa no na especificao do MySQL. Alm disso, atravs das chaves
contar com DBAs em seu time) ou delegar a atividade a um admi- estrangeiras (FOREIGN KEY) configuramos os relacionamentos
nistrador de banco de dados (DBA), que se encarrega de escrever entre as tabelas.
os scripts de criao do banco e fazer as alteraes.
O script para criao do banco de dados da aplicao exemplo Camada de Persistncia
mostrado na Listagem 1 e tem o objetivo de criar a base de Iniciaremos a implementao do nosso diagrama criando
dados, isto , as tabelas e seus atributos, em um banco de dados a camada de persistncia. Para isso, com o intuito de manter
MySQL, j considerando a especificao de chaves primrias, uma boa organizao do cdigo, crie o pacote database, local
estrangeiras e nicas. onde as classes relacionadas a este requisito devem ser imple-
mentadas.
Listagem 1. Script para criao do banco de dados da aplicao exemplo. Na Listagem 2 apresentada a primeira classe da camada
de persistncia, DatabaseManager, a qual tem a funo de es-
create database Estoque;
tabelecer a conexo com o banco de dados e executar algumas
create table Fornecedor ( consultas SQL.
codigoFornecedor int,
endereco varchar(100),
telefone varchar(15), Listagem 2. Cdigo da classe DatabaseManager.
nome varchar(100),
PRIMARY KEY (codigoFornecedor), 01. package database;
UNIQUE KEY (nome)
02. import java.sql.*;
);
03.
create table Unidade( 04. public class DatabaseManager {
codigoUnidade int, 05.
sigla varchar(10), 06. private static final String JDBC_DRIVER = com.mysql.jdbc.Driver;
descricao varchar(100), 07. private static final String DB_URL = jdbc:mysql://localhost/Estoque;
PRIMARY KEY (codigoUnidade),
08. private static final String USER = root;
UNIQUE KEY (sigla)
09. private static final String PASSWORD = password;
);
10. private Connection connection;
create table Produto( 11.
codigoProduto int, 12. public DatabaseManager() throws SQLException, ClassNotFoundException {
nomeProduto varchar(15), 13. Class.forName(JDBC_DRIVER);
codigoBarras varchar(20), 14. connection = DriverManager.getConnection(DB_URL, USER, PASSWORD);
estoque float,
15. }
descricao varchar(100),
valorProduto float, 16.
codigoUnidade int, 17. public void executeSQL(String sql) throws SQLException {
PRIMARY KEY (codigoProduto), 18. Statement statement = null;
FOREIGN KEY (codigoUnidade) REFERENCES Unidade (codigoUnidade), 19. statement = connection.createStatement();
UNIQUE KEY (nomeProduto), 20. statement.execute(sql);
UNIQUE KEY (descricao) 21. statement.close();
);
22. }
create table Pedido( 23.
codigoPedido int, 24. public ResultSet executeQuery(String sql) throws SQLException {
dataPedido date, 25. Statement statement = null;
valorPedido float, 26. statement = connection.createStatement();
codigoFornecedor int, 27. return statement.executeQuery(sql);
PRIMARY KEY (codigoPedido),
28. }
FOREIGN KEY (codigoFornecedor) REFERENCES Fornecedor (codigoFornecedor)
29.
);
30. public PreparedStatement prepararStatament(String sql) throws SQLException {
create table ItemPedido( 31. PreparedStatement statement;
codigoItem int, 32. statement = connection.prepareStatement(sql);
codigoPedido int, 33. return statement;
codigoProduto int, 34. }
quantidade float,
35.
valorItem float,
PRIMARY KEY (codigoItem), 36. public void setAutoCommit(boolean autocommit) throws SQLException {
FOREIGN KEY (codigoPedido) REFERENCES Pedido (codigoPedido), 37. connection.setAutoCommit(autocommit);
FOREIGN KEY (codigoProduto) REFERENCES Produto (codigoProduto) 38. }
); 39. }

Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia 7


UML e Java na prtica

Para que DatabaseManager funcione corretamente, necessrio Listagem 3. Cdigo da classe FornecedorSQL.

ter o banco de dados MySQL instalado e em execuo com a base de 01. package database;
dados descrita na Listagem 1. A partir disso, para que a aplicao 02.
03. public class FornecedorSQL {
consiga se conectar base, deve-se adicionar o conector de acesso ao
04.
banco no classpath da aplicao. Este conector, tambm conhecido 05. public static String insert = insert into Fornecedor
como driver JDBC, pode ser baixado do site do MySQL. 06. + (codigoFornecedor, endereco, telefone, nome)
07. + values (?,?,?,?);
Na Listagem 2, o driver de acesso carregado na linha 6. Na
08.
linha 7, declarada a URL de acesso ao banco (repare no sufixo 09. public static String update = UPDATE Fornecedor SET +
o nome do banco), e nas linhas 8 e 9 so informados o usurio e 10. codigoFornecedor = ?, +
11. endereco = ?, +
a senha da base. 12. telefone = ?, +
Nesta classe tambm foram implementados os mtodos execu- 13. nome = ? +
teSQL() e executeQuery(), responsveis por executar diretamente 14. WHERE codigoFornecedor = ?;
15.
qualquer comando SQL (vide linhas 17 a 28), e o mtodo prepa- 16. public static String delete = delete from Fornecedor
rarStatement(), criado para que seja possvel preparar comandos 17. + where codigoFornecedor = ?;
SQL que so executados com frequncia mais alta e assim garantir 18.
19. public static String selectAll = select * from Fornecedor;
um melhor desempenho (vide linhas 30 a 34). 20.
Por fim, tem-se o mtodo setAutoCommit(), que permite 21. public static String select = select * from Fornecedor
criar transaes, ou seja, executar conjuntos de comandos SQL 22. + where codigoFornecedor = ?;
23. }
de forma atmica. Para tanto, basta iniciar a transao com
setAutoCommit(false), o que faz com que os prximos comandos Listagem 4. Cdigo da classe UnidadeSQL.
SQL enviados atravs da conexo com o banco de dados no sejam 01. package database;
executados prontamente, e terminar com setAutoCommit(true), 02.
o que efetiva todos os SQLs pendentes na conexo. 03. public class UnidadeSQL {
04.
Visto que optamos por usar PreparedStatements para otimizar a 05. public static String insert = insert into Unidade
eficincia da aplicao e do banco de dados, deixaremos os scripts 06. + (codigoUnidade, sigla, descricao)
SQL de criao, edio, excluso e consulta de registros de cada 07. + values (?,?,?);
08.
entidade em uma classe especfica. O primeiro exemplo disso 09. public static String update = UPDATE Unidade SET +
pode ser verificado na Listagem 3. 10. codigoUnidade = ?, +
O cdigo-fonte apresentado nessa listagem contm os comandos 11. sigla = ?, +
12. descricao = ? +
SQL voltados para as operaes bsicas de cadastro de fornece- 13. WHERE codigoUnidade = ?;
dores a serem usados em PreparedStatements. Note que para 14.
15. public static String delete = delete from Unidade
especificar os parmetros de cada comando so utilizadas inter-
16. + where codigoUnidade = ?;
rogaes, como demonstram as instrues de insert (linha 5), 17.
update (linha 9), delete (linha 16) e select (linhas 21). Observe 18. public static String selectAll = select * from Unidade;
19.
ainda que existem dois comandos select: um para consultar um
20. public static String select = select * from Unidade
fornecedor pelo cdigo (linha 21) e outro para consultar todos os 21. + where codigoUnidade = ?;
fornecedores (linha 19). 22. }
Uma melhoria que pode ser realizada ao esquema apresentado
adicionar o comando LIMIT nos SQLs de consulta, a fim de
evitar o alto uso de memria no caso de as tabelas conterem um De acordo com os padres selecionados na fase de projeto, esta
nmero muito grande de registros. camada ser dividida em DTOs e DAOs, artefatos que correspon-
De forma semelhante, na Listagem 4 so apresentados os coman- dem a objetos de transmisso de dados e objetos de acesso a dados,
dos SQL para o cadastro de unidades. Como o padro de consulta respectivamente. Comecemos a implementao, ento, pela classe
o mesmo, no necessrio explicar o seu cdigo. O mesmo vale FornecedorDto, que responsvel por conter todas as regras de
para as classes que implementam as operaes relacionadas a negcio relacionadas ao cadastro de fornecedores. O seu cdigo
produtos, pedidos e itens pedidos. O cdigo-fonte destas pode apresentado na Listagem 5 e para manter as boas prticas da
ser verificado no arquivo disponibilizado para download nesta organizao de pacotes, crie-a dentre do pacote negocio.dto.
edio. Como verificado, essa classe deve ser implementada de forma
que cada objeto contenha todos os dados relativos a um forne-
Camada de Negcio cedor, o que envolve os atributos codigoFornecedor, endereco,
Concluda a camada de persistncia, pode-se partir para a telefone e nome (vide linhas 4 a 7). Essa classe tambm contm o
camada de negcios, local onde devemos implementar, dentre construtor default (linhas 9 a 10), que possibilita criar um objeto
outras coisas, as regras de negcio da aplicao. sem informar os valores dos campos. Para definir o valor de cada

8 Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia


Listagem 5. Cdigo da classe FornecedorDto.

01. package negocio.dto; 25. return endereco;


02. 26. }
03. public class FornecedorDto { 27.
04. int codigoFornecedor; 28. public void setEndereco(String endereco) {
05. String endereco; 29. this.endereco = endereco;
06. String telefone; 30. }
07. String nome; 31.
08. 32. public String getTelefone() {
09. public FornecedorDto() { 33. return telefone;
10. } 34. }
11. 35.
12. public String toString() { 36. public void setTelefone(String telefone) {
13. return codigoFornecedor + - + nome; 37. this.telefone = telefone;
14. } 38. }
15. 39.
16. public int getCodigoFornecedor() { 40. public String getNome() {
17. return codigoFornecedor; 41. return nome;
18. } 42. }
19. 43.
20. public void setCodigoFornecedor(int codigoFornecedor) { 44. public void setNome(String nome) {
21. this.codigoFornecedor = codigoFornecedor; 45. this.nome = nome;
22. } 46. }
23. 47. }
24. public String getEndereco() {

campo podem ser utilizados os respectivos setters, definidos nesta atravs de PreparedStatements os scripts SQL de insero, edio,
classe. E para recuperar o valor de um campo, pode ser utilizado excluso e consulta so executados mais rapidamente, pois o banco
o getter correspondente. de dados os mantm preparados em memria, alterando apenas
Outro mtodo presente na classe FornecedorDto o toString(). os parmetros a cada vez que so chamados.
Este retorna uma representao na forma de String do objeto e Os PreparedStatements declarados em UnidadeDao so inicia-
ser usado na camada de apresentao para criar uma descrio lizados no construtor atravs da chamada ao mtodo prepararS-
curta de um fornecedor. tatement(), da classe DatabaseManager, deixando os mesmos
Em seguida, classes semelhantes devem ser criadas para im- SQLs prontos no banco de dados para execuo quando a aplicao
plementar os DTOs das unidades de medida, produtos, pedidos estiver rodando. Assim no ser preciso construir novamente os
e itens pedidos. SQLs caso seja criada uma nova instncia de UnidadeDao. Note,
Como existe uma relao entre as classes Produto e Unidade, ainda, que a inicializao dos mesmos acontece no construtor.
conforme indicado no diagrama de classes (vide Figura 5), em Nas linhas 29 a 39 declarado o mtodo criarUnidade(). Este
ProdutoDto criada uma referncia para UnidadeDto, de forma recebe UnidadeDto como parmetro, a partir deste define os
que cada produto tenha uma unidade de medida. parmetros no PreparedStatement insert e executa o SQL para
O mesmo ocorre em PedidoDto, o qual, alm dos campos es- criar uma nova unidade de medida no banco de dados. De
pecificados no diagrama de classes, possui o campo fornecedor, forma anloga, os mtodos editarUnidade(), excluirUnidade()
de tipo FornecedorDto, por causa do relacionamento da classe e consultarUnidade() recebem um DTO como parmetro, ali-
Pedido com Fornecedor, sinalizando um pedido de compra. mentam o PreparedStatement com os valores por ele esperados
Concluindo a implementao dos DTOs, um raciocnio seme- e executam o SQL correspondente para aplicar as alteraes no
lhante pode ser verificado em ItemPedidoDto, que declara os banco de dados.
atributos produto e pedido, derivados dos relacionamentos de Uma exceo o mtodo consultarTodasUnidades(), que no
ItemPedido com Produto e Pedido. recebe parmetros por ser responsvel por consultar e retornar
Outro padro de projeto usado na aplicao exemplo o DAO. todos os registros da tabela Unidade.
Este define objetos que encapsulam o cdigo de acesso ao banco O cdigo de FornecedorDao segue a mesma proposta de Unida-
de dados. Para tanto, os DAOs acessam a camada de persistncia deDao e, portanto, no ser exibido. J o cdigo de ProdutoDao
para obter a conexo com o banco, executar SQLs para inserir, apresentado nas Listagens 8 e 9. Essa classe funciona de forma
editar, excluir ou consultar registros, entre outras funes. Nas anloga aos demais DAOs, porm o tratamento do seu campo
Listagens 6 e 7 apresentado o cdigo da classe UnidadeDao. unidade (do tipo UnidadeDto) diferente, uma vez que ele pro-
Nas linhas 13 a 17 dessa classe so declarados um PreparedS- veniente de um relacionamento entre as classes ProdutoDto e Uni-
tatement para cada SQL definido em UnidadeSQL, pertencente dadeDto. Sendo assim, o cdigo da unidade obtido atravs da
camada de persistncia. Um ganho importante com isso que chamada ao mtodo getCodigoUnidade() do objeto unidade.

Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia 9


UML e Java na prtica

Alm disso, nas consultas, para cada objeto do tipo ProdutoDto Concluda essa etapa, vlido ressaltar que podemos implemen-
criado, criado tambm um UnidadeDto, que consultado no tar o cdigo relacionado ao acesso a dados de uma maneira mais
banco de dados usando o DAO UnidadeDao informado no cons- simples, explorando frameworks Java criados exatamente com
trutor. Deste modo, a informao consultada no se restringe esse intuito. Um bom exemplo o Hibernate, que abstrai, dentre
apenas aos dados do produto, pois tambm so buscados os dados outras coisas, a necessidade de escrita do cdigo SQL. Dito isso,
da unidade de medida do mesmo. a partir de artigos j publicados nesta revista sobre esse tema, o
Com cdigo semelhante, temos ainda os DAOs PedidoDao e leitor pode buscar realizar essa refatorao em nosso exemplo e
ItemPedidoDao, que foram omitidos por questo de espao. consequentemente explorar novos conceitos.

Listagem 6. Cdigo da classe UnidadeDao Parte 1.

01. package negocio.dao; 32. insert.setString(2, unidade.getSigla());


02. 33. insert.setString(3, unidade.getDescricao());
03. import java.sql.PreparedStatement; 34. insert.executeUpdate();
04. import java.sql.ResultSet; 35. }
05. import java.sql.SQLException; 36. catch (SQLException e) {
06. import java.util.ArrayList; 37. e.printStackTrace();
07. import database.DatabaseManager; 38. }
08. import database.UnidadeSQL; 39. }
09. import negocio.dto.UnidadeDto; 40.
10. 41. public void editarUnidade(UnidadeDto unidade){
11. public class UnidadeDao { 42. try {
12. 43. update.setInt (1, unidade.getCodigoUnidade());
13. private PreparedStatement insert; 44. update.setString(2, unidade.getSigla());
14. private PreparedStatement update; 45. update.setString(3, unidade.getDescricao());
15. private PreparedStatement delete; 46. update.setInt (4, unidade.getCodigoUnidade());
16. private PreparedStatement selectAll; 47. update.executeUpdate();
17. private PreparedStatement select; 48. }
18. 49. catch (SQLException e) {
19. public UnidadeDao(DatabaseManager databaseManager) throws SQLException { 50. e.printStackTrace();
20. 51. }
21. insert = databaseManager.prepararStatament(UnidadeSQL.insert); 52. }
22. update = databaseManager.prepararStatament(UnidadeSQL.update); 53.
23. delete = databaseManager.prepararStatament(UnidadeSQL.delete); 54. public void excluirUnidade(UnidadeDto unidade){
24. select = databaseManager.prepararStatament(UnidadeSQL.select); 55. try {
25. selectAll = databaseManager.prepararStatament(UnidadeSQL.selectAll); 56. delete.setInt (1, unidade.getCodigoUnidade());
26. 57. delete.executeUpdate();
27. } 58. }
28. 59. catch (SQLException e) {
29. public void criarUnidade(UnidadeDto unidade){ 60. e.printStackTrace();
30. try { 61. }
31. insert.setInt (1, unidade.getCodigoUnidade()); 62. }

Listagem 7. Cdigo da classe UnidadeDao Parte 2.

63. public ArrayList<UnidadeDto> consultarTodasUnidades() { 83. try {


64. ArrayList<UnidadeDto> lista = new ArrayList<UnidadeDto>(); 84. select.setInt(1, codigoUnidade);
65. try { 85. ResultSet rs = select.executeQuery();
66. ResultSet rs = selectAll.executeQuery(); 86. if (rs.next()) {
67. while (rs.next()) { 87. UnidadeDto unidade = new UnidadeDto();
68. UnidadeDto unidade = new UnidadeDto(); 88. unidade.setCodigoUnidade(rs.getInt(codigoUnidade));
69. unidade.setCodigoUnidade(rs.getInt(codigoUnidade)); 89. unidade.setSigla(rs.getString(sigla));
70. unidade.setSigla(rs.getString(sigla)); 90. unidade.setDescricao(rs.getString(descricao));
71. unidade.setDescricao(rs.getString(descricao)); 91. return unidade;
72. lista.add(unidade); 92. }
73. } 93. return null;
74. return lista; 94. }
75. } 95. catch (SQLException e) {
76. catch (SQLException e) { 96. e.printStackTrace();
77. e.printStackTrace(); 97. return null;
78. return null; 98. }
79. } 99.
80. } 100. }
81. 101. }
82. public UnidadeDto consultarUnidade(int codigoUnidade) {

10 Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia


Listagem 8. Cdigo da classe ProdutoDao Parte 1.

01. package negocio.dao; 33. public void criarProduto(ProdutoDto produto){


02. 34. try {
03. import java.sql.PreparedStatement; 35. insert.setInt (1, produto.getCodigoProduto());
04. import java.sql.ResultSet; 36. insert.setString(2, produto.getNomeProduto());
05. import java.sql.SQLException; 37. insert.setString(3, produto.getCodigoBarras());
06. import java.util.ArrayList; 38. insert.setFloat (4, produto.getEstoque());
07. 39. insert.setString(5, produto.getDescricao());
08. import database.DatabaseManager; 40. insert.setFloat (6, produto.getValorProduto());
09. import database.ProdutoSQL; 41. insert.setInt (7, produto.getUnidade().getCodigoUnidade());
10. import negocio.dto.ProdutoDto; 42. insert.executeUpdate();
11. import negocio.dto.UnidadeDto; 43. }
12. 44. catch (SQLException e) {
13. public class ProdutoDao { 45. e.printStackTrace();
14. 46. }
15. private static PreparedStatement insert; 47. }
16. private static PreparedStatement update; 48.
17. private static PreparedStatement delete; 49. public void editarProduto(ProdutoDto produto){
18. private static PreparedStatement selectAll; 50. try {
19. private static PreparedStatement select; 51. update.setInt (1, produto.getCodigoProduto());
20. private UnidadeDao unidadeDao; 52. update.setString(2, produto.getNomeProduto());
21. 53. update.setString(3, produto.getCodigoBarras());
22. public ProdutoDao(DatabaseManager databaseManager, 54. update.setFloat (4, produto.getEstoque());
UnidadeDao unidadeDao) throws SQLException { 55. update.setString(5, produto.getDescricao());
23. this.unidadeDao = unidadeDao; 56. update.setFloat (6, produto.getValorProduto());
24. synchronized (this) { 57. update.setInt (7, produto.getUnidade().getCodigoUnidade());
25. insert = databaseManager.prepararStatament(ProdutoSQL.insert); 58. update.setInt (8, produto.getCodigoProduto());
26. update = databaseManager.prepararStatament(ProdutoSQL.update); 59. update.executeUpdate();
27. delete = databaseManager.prepararStatament(ProdutoSQL.delete); 60. }
28. select = databaseManager.prepararStatament(ProdutoSQL.select); 61. catch (SQLException e) {
29. selectAll = databaseManager.prepararStatament(ProdutoSQL.selectAll); 62. e.printStackTrace();
30. } 63. }
31. } 64. }
32.

Listagem 9. Cdigo da classe ProdutoDao Parte 2.

01. public void excluirProduto(ProdutoDto produto){ 29. e.printStackTrace();


02. try { 30. return null;
03. delete.setInt (1, produto.getCodigoProduto()); 31. }
04. delete.executeUpdate(); 32. }
05. } 33.
06. catch (SQLException e) { 34. public ProdutoDto consultarProduto(int codigoProduto) {
07. e.printStackTrace(); 35. try {
08. } 36. select.setInt(1, codigoProduto);
09. } 37. ResultSet rs = select.executeQuery();
10. 38. if (rs.next()) {
11. public ArrayList<ProdutoDto> consultarTodosProdutos() { 39. ProdutoDto produto = new ProdutoDto();
12. ArrayList<ProdutoDto> lista = new ArrayList<ProdutoDto>(); 40. produto.setCodigoProduto(rs.getInt(codigoProduto));
13. try { 41. produto.setNomeProduto(rs.getString(nomeProduto));
14. ResultSet rs = selectAll.executeQuery(); 42. produto.setCodigoBarras(rs.getString(codigoBarras));
15. while (rs.next()) { 43. produto.setEstoque(rs.getFloat(estoque));
16. ProdutoDto produto = new ProdutoDto(); 44. produto.setDescricao(rs.getString(descricao));
17. produto.setCodigoProduto(rs.getInt(codigoProduto)); 45. produto.setValorProduto(rs.getFloat(valorProduto));
18. produto.setNomeProduto(rs.getString(nomeProduto)); 46. produto.setUnidade(unidadeDao.consultarUnidade(rs.getInt(codigoUnidade)));
19. produto.setCodigoBarras(rs.getString(codigoBarras)); 47. return produto;
20. produto.setEstoque(rs.getFloat(estoque)); 48. }
21. produto.setDescricao(rs.getString(descricao)); 49. return null;
22. produto.setValorProduto(rs.getFloat(valorProduto)); 50. }
23. produto.setUnidade(unidadeDao.consultarUnidade(rs.getInt 51. catch (SQLException e) {
(codigoUnidade))); 52. e.printStackTrace();
24. lista.add(produto); 53. return null;
25. } 54. }
26. return lista; 55. }
27. } 56. }
28. catch (SQLException e) {

Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia 11


UML e Java na prtica

Camada de Apresentao
A camada de apresentao proposta para a aplicao exemplo
foi implementada usando Swing. No entanto, outras tecnologias
poderiam ter sido empregadas como, por exemplo, AWT, JavaFX
ou, ainda, considerando-se que a camada de apresentao se
torne acessvel via web, tecnologias como JSP (JavaServer Pages) e
JSF (JavaServer Faces).
As telas da aplicao sero mostradas nas imagens a seguir,
mas o cdigo-fonte foi omitido, por no fazer parte do escopo
deste artigo. Na Figura 6 temos a tela principal do software, que
permite o acesso a todos os casos de uso da aplicao de controle
de estoque.
Ao selecionar a primeira opo, Cadastro de Fornecedor, a janela
exposta na Figura 7 apresentada a qual contm todos os casos
de uso relacionados a fornecedor (vide Figura 1) oferecendo
acesso s operaes de criao, edio e excluso de fornecedo-
res. O mesmo vale para as telas exibidas nas Figuras 8, 9 e 10,
Figura 6. Tela principal da aplicao exemplo que viabilizam o acesso s funcionalidades de listagem, criao,
edio e excluso de unidades de medidas, produtos e pedidos,
respectivamente.
Como verificado, a linguagem UML uma poderosa ferramenta
de modelagem de software e apresenta diversos diagramas que
auxiliam as atividades de desenvolvimento. Consequentemente,
sua adoo possibilita um aumento da qualidade da documen-
tao produzida nas fases de anlise e projeto, assim como uma
melhora da legibilidade e manutenibilidade do cdigo, da comu-
nicao entre os desenvolvedores, entre outros fatores.
Figura 7. Tela do cadastro de fornecedores Diante disso, empresas que primam por qualidade e bons pro-
jetos de software exigem dos desenvolvedores cada vez mais o
domnio dos principais diagramas dessa linguagem de modela-
gem, pois isso implica diretamente na boa converso dos mesmos
em cdigo-fonte correto e eficiente.

Autor
John Soldera
johnsoldera@gmail.com
Figura 8. Tela do cadastro de unidades de medida bacharel em Cincias da Computao pela UCS (Universidade
de Caxias do Sul), mestre em Computao Aplicada pela Uni-
sinos e doutor em Cincias da Computao pela UFRGS (Universidade
Federal do Rio Grande do Sul). Trabalha com Java h 12 anos e possui
a certificao SCJP.

Links:

Figura 9. Tela do cadastro de produtos Javadoc da plataforma Java SE 8.


https://docs.oracle.com/javase/8/docs/api/

Pgina oficial do Hibernate.


http://hibernate.org/

Pgina oficial do MySQL.


https://www.mysql.com/
Figura 10. Tela do cadastro de pedidos

12 Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia


Refatorando cdigo com
padres de projeto
Veja neste artigo uma abordagem prtica para
melhorar a qualidade do cdigo com os padres
Prototype, Strategy e Adapter

O
desenvolvimento de software de qualidade
um processo que exige tempo e um elevado Fique por dentro
esforo por parte da equipe do projeto. Para A utilizao de padres de projeto permite o desenvolvimento de
manter o padro alto primordial evitar o uso de m- um cdigo limpo, flexvel e testvel, assim como facilita a comunica-
todos antiquados ou inapropriados, como codificar de o entre arquitetos e desenvolvedores ao viabilizar um vocabulrio
forma estruturada. Alm disso, necessrio escrever comum, amenizando possveis problemas de interpretao, algo
cdigo pensando tambm na sua facilidade de manu- presente em projetos de software. Com base nisso, este artigo til
teno e evoluo. Com essas medidas o processo de por apresentar uma maneira prtica para deteco de problemas de
desenvolvimento tende a se tornar mais caro, mas o design no cdigo e como refator-lo empregando boas prticas ao
custo para corrigir os problemas e manter o software introduzir padres de projeto ao ciclo de desenvolvimento.
ser ainda mais alto sem aplic-las.
Em sistemas em que no houve essa preocupao a
refatorao ser um processo bastante complexo ou mes- sibilita focar no que um objeto e qual comportamento ele ter
mo invivel, pois o cdigo provavelmente apresentar antes mesmo de comear a ser implementado.
baixa coeso, alto acoplamento, entre outros indcios J o encapsulamento consiste em adicionar segurana aplica-
que sinalizam a baixa qualidade. Em alguns casos chega o. Isso porque atravs deste conceito haver a separao entre
a ser mais aconselhvel criar um novo sistema do que aspectos externos e implementaes internas de um objeto, como
tentar modific-lo. viabilizado pelos modificadores de acesso. Assim, evita-se que o
Diante disso, aplicar tcnicas que amenizem a pro- software crie uma interdependncia excessiva, que normalmente
duo de cdigo ruim essencial, como a orientao a chamamos de alto acoplamento, entre objetos e que uma mudana
objetos e padres de projeto, utilizadas para alcanar possa gerar efeitos colaterais em todo o sistema.
um alto nvel de satisfao na produo do cdigo. Es- O conceito de herana, por sua vez, proporciona que estruturas
sas tcnicas, se aplicadas corretamente, permitiro um comuns sejam compartilhadas entre diferentes classes, e assim,
cdigo mais fcil de ser mantido. Alm disso, permitir mtodos e atributos podem ser reutilizados, evitando possveis
que o sistema seja estendido, isto , receba novas fun- problemas como cdigo duplicado.
cionalidades, de forma mais simples. Esses fundamentos da orientao a objetos, junto com os concei-
Com base no que foi apresentado, este artigo dar uma tos de padres de projeto, ajudaro o profissional a produzir um
viso geral sobre padres de projeto e como eles so cdigo de qualidade e a reduzir o esforo necessrio no decorrer
utilizados na linguagem Java. Em seguida, explanar do desenvolvimento do software e de sua manuteno.
sobre como refatorar um projeto exemplo aplicando os
padres Prototype, Strategy e Adapter. Padres de projeto ou Padres GoF
O conceito padro de projeto surgiu com o arquiteto austraco
Fundamentos da orientao a objetos Christopher Alexander. Ele constatou que por conta do emprego
O paradigma da orientao a objetos estabelece fun- de padres as cidades medievais eram mais bonitas e harmnicas.
damentos que influenciam diretamente a organizao e O resultado dessa observao foi a publicao do livro A Pattern
qualidade do cdigo, como abstrao, encapsulamento Language, em meados de 1970, em que ele apresenta como utilizar
e herana. O conceito da abstrao, por exemplo, pos- padres em construes futuras ou na melhoria das j existentes.

Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia 13


Refatorando cdigo com padres de projeto

J no mbito da Engenharia de Software, o termo comeou a classe e objeto. A utilizao desses padres auxilia o sistema
ser utilizado por Kent Beck e Ward Cunningham, em meados de a ser independente de como seus objetos so criados, compos-
1980. Porm, somente em 1995, quando Erich Gamma, Richard tos e representados. Isso ocorre devido ao encapsulamento do
Helm, Ralph Johnson e John Vlissides publicaram o livro Design conhecimento sobre as classes concretas que sero usadas pela
Patterns Elements of Reusable Object-Oriented Software, considerado aplicao e tambm pela ocultao do modo como essas classes
a referncia mais importante sobre o assunto, os padres de projeto so criadas e formadas.
comearam a ter notoriedade na rea da computao. Aps isso, os A Tabela 1 apresenta os seis padres criacionais e os seus
autores ficaram conhecidos como a A Gangue dos Quatro, ou Gang objetivos.
of Four (GoF). Foi da que surgiu a nomenclatura Padres GoF.
O livro est dividido em trs categorias, a saber: padres de Padres estruturais
criao, estruturais e comportamentais. Ao todo so vinte e trs Como o prprio nome diz, os padres dessa categoria esto
padres catalogados e que descrevem solues para diversos relacionados com a estrutura dos objetos. Eles se preocupam com
problemas recorrentes durante o processo de desenvolvimento, a composio das classes e dos objetos e com o relacionamento
como ser visto a seguir. entre eles.
O objetivo destes padres, descritos na Tabela 2, facilitar o
Padres de criao design do sistema identificando maneiras de realizar o relaciona-
Os padres de criao tm a funo de abstrair o processo de mento entre as entidades, deixando o desenvolvedor livre desta
criao de objetos e podem ser divididos em duas categorias: preocupao.

Padres de projeto Objetivo


Prover uma interface para criar uma famlia de objetos relacionados ou dependentes sem especificar suas classes concretas. O Abstract Window
Abstract Factory
Toolkit (AWT) utiliza esse padro para fornecer um conjunto de classes independentes de plataforma especficas para operaes grficas.
Separar o processo de construo de objetos complexos de sua representao, de modo que um mesmo processo possa gerar diferentes
Builder representaes de forma transparente. Um bom exemplo a classe java.lang.ProcessBuilder, utilizada para executar comandos em sistemas
operacionais.
Encapsular a escolha da classe concreta a ser utilizada na criao de um determinado tipo de objeto. O mtodo Calendar.getInstance() uma
Factory Method
implementao da proposta definida pelo Factory Method, pois ele encapsula a forma de criar um novo objeto concreto (Calendar).
Permitir a criao de um novo objeto atravs da cpia das propriedades de um objeto existente. Em outras palavras, ele usa uma instncia de
Prototype uma classe para criar uma nova, mas que possui propriedades idnticas inicial. As classes que implementam a interface java.lang.Cloneable,
por exemplo, utilizam o mtodo java.lang.Object.clone() para criar cpias de si mesma.
Garantir que uma classe tenha somente uma instncia e fornecer um ponto global de acesso mesma. A classe java.lang.Runtime um exemplo
Singleton de Singleton implementado pela JVM, pois cada aplicativo Java tem uma nica instncia dessa classe que permite interao entre o aplicativo e
o ambiente em que executado.

Tabela 1. Padres de projetos criacionais

Padres de projeto Objetivo


Converter a interface de uma classe em outra que possa ser utilizada por clientes. Assim, classes com interfaces incompatveis podero trabalhar
Adapter em conjunto, atravs da interface de adaptao. Por exemplo, o java.io.InputStreamReader recebe uma cadeia de bytes (java.io.InputStream) e
os adapta para caracteres (java.io.Reader).
Desacoplar uma abstrao de sua implementao, de modo que ambas variem de maneira independente. Esse padro facilmente encontrado
Bridge
nas bibliotecas de drivers como, por exemplo, as que fazem acesso JDBC ao banco de dados.
Agrupar objetos que fazem parte de uma relao parte-todo de forma a trat-los sem distino. O mtodo addAll(Collection) de java.util.List
Composite
implementa o padro Composite para adicionar os objetos de uma coleo ao final da lista especificada.
Permitir que funcionalidades sejam adicionadas a um objeto existente em tempo de execuo, sem alterar a sua estrutura. Em outras palavras,
esse padro cria uma classe decoradora que ir envolver a classe original e fornecer mtodos adicionais para manipul-la, a fim de manter sua
Decorator
estrutura intacta. Um exemplo de aplicao real desse design pattern a classe java.io.BufferedOutputStream, pois ela recebe em seu constru-
tor um objeto java.io.OutputStream e o decora.
Encapsular o acesso a uma funcionalidade de um sistema ou mdulo, a fim de simplificar seu uso e fornecer uma interface mais amigvel. A
Facade
classe java.awt.Graphics, por exemplo, uma fachada que oferece mtodos simples para as operaes relacionadas aos grficos.
Compartilhar, de forma eficiente, objetos que so usados em grande quantidade. Assim possvel reduzir o nmero de objetos criados, aumen-
Flyweight tar o desempenho e amenizar o consumo da memria. O mtodo valueOf(long) da classe java.lang.Long um timo exemplo de implementa-
o desse padro, pois ele faz uso de cache interno.
Controlar as chamadas a um objeto por meio de outro de mesma interface, ou seja, ele fornece um objeto substituto (proxy) ao verdadeiro.
Proxy Assim, esse proxy poder interceptar as chamadas aos mtodos originais e adicionar aes antes ou depois do seu uso, como validar a restrio
de segurana. Essa a ideia do java.lang.reflect.Proxy.

Tabela 2. Padres de projetos estruturais

14 Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia


Padres comportamentais de agora ser apresentado um exemplo de um jogo de robs com
Os padres comportamentais fornecem estratgias consolidadas problemas arquiteturais que podem ser solucionados atravs de
para modelar a maneira como os objetos colaboram entre si. A refatorao aplicando os padres Prototype, Strategy e Adapter.
partir disso, viabilizam a reduo do acoplamento e tornam o Imagine que esse jogo era implementado por uma empresa e foi
cdigo mais preparado para receber novas funes/extenses. vendido para outra que tem em sua equipe de desenvolvimento
Vejamos um exemplo para facilitar a compreenso dessa defini- profissionais com bastante experincia. A partir de agora esses pro-
o: imagine um sistema que possui suas configuraes em um fissionais estaro encarregados de melhor-lo, pois h relatos que o
arquivo de texto e todas as vezes que esse arquivo for alterado jogo lento quando h muitos robs participando de uma partida.
preciso que o sistema seja reconfigurado com os novos valores. O jogo consiste em uma batalha onde os robs podem se movi-
Para atender esse requisito, o padro de projeto Observer foi im- mentar em um tabuleiro e ao detectar que h um oponente pr-
plementado. Assim, sempre que o arquivo for alterado o sistema ximo ele deve realizar uma srie de comportamentos para atingir
ser notificado para atualizar seu comportamento de acordo com o oponente ou fugir. Alm disso, uma caracterstica importante
as novas especificaes. que todos os robs devem possuir os mesmos atributos, como
Estes padres, descritos na Tabela 3, tratam da forma como fora e velocidade. Essa regra foi definida para tornar a partida
as entidades se comportam. Isto , eles auxiliam a comunicao mais justa.
entre os objetos distribuindo as responsabilidades e definindo a Diante disso, os desenvolvedores fizeram uma anlise no cdigo
comunicao interna. e detectaram alguns pontos que podem ser melhorados com a
adoo de padres de projetos. Em seguida, para acompanhar a
Aplicando os padres Prototype, Strategy e Adapter evoluo do cdigo, optaram por criar uma partida com apenas
Padro de projeto no cdigo pronto para ser reaproveitado trs robs.
no desenvolvimento de software. Na verdade, ele um modelo Na Listagem 1 apresentada a classe Jogo, artefato que repre-
abstrato para resolver determinado problema. Dito isto, a partir senta o tabuleiro onde os robs realizam as batalhas.

Padres de projeto Objetivo


Promover o desacoplamento entre o objeto solicitante e o solicitado, dando oportunidade a diversos objetos de tratar a solicitao, ou
seja, os objetos receptores sero encadeados e transmitidos solicitao atravs de uma cadeia at que um objeto o trate. Um exemplo
Chain of responsibility
de aplicao desse padro o tratamento de excees, no qual uma exceo recursivamente escala a pilha de mtodos at encontrar um
capaz de trat-la.
Encapsular uma solicitao como objeto, a fim de simplificar a execuo encadeada de comandos. Assim, as operaes podem ser enfi-
Command
leiradas, registradas ou desfeitas. As implementaes de java.lang.Runnable e javax.swing.Action utilizam esse padro.
Dada uma linguagem, por exemplo, o formato de exibio de uma data, tem a funo de definir uma representao para sua gramtica
Interpreter juntamente com um interpretador, que, por sua vez, usa a representao para compreender sentenas dessa linguagem. As subclasses
de java.text.Format fazem uso do padro Interpreter.
Fornecer um modo eficiente para percorrer sequencialmente os elementos de uma coleo, sem que a estrutura interna dessa coleo
Iterator
seja exposta. Todas as implementaes de java.util.Iterator fazem uso desse padro.
Definir um objeto que encapsula a forma como um conjunto de objetos interage. O Mediator promove o acoplamento fraco ao evitar
Mediator que os objetos se refiram uns aos outros explicitamente e possibilita variar suas interaes independentemente. Todos os mtodos
scheduleXXX() da classe java.util.Timer so exemplos de implementao desse design pattern.
Capturar e externalizar o estado interno de um objeto, sem violar o encapsulamento, de modo que ele possa ser restaurado posterior-
Memento
mente. A classe java.util.Date um exemplo para esse padro, pois internamente faz uso de um long para armazenar o valor da data.
Definir um mecanismo eficiente para reagir s alteraes realizadas em determinados objetos. A interface javax.faces.event.PhaseListe-
Observer
ner, por exemplo, permite notificar o incio e o fim de cada fase do ciclo de uma requisio.
Alterar o comportamento de um determinado objeto de acordo com o estado no qual ele se encontra. A classe javax.faces.lifecycle.
State LifeCycle, por exemplo, tem dependncia do estado do ciclo de vida do JSF. Assim, se a fase for para restaurar a cama de viso (Restore
view), o comportamento ser o de construir os elementos da tela, fazer validaes nos componentes e salvar a view no FacesContext.
Definir uma famlia de algoritmos, encapsular cada uma delas e torn-las intercambiveis. Strategy propicia que o algoritmo varie inde-
Strategy pendente dos clientes que o utilizam. O mtodo compare() da interface java.util.Comparator, muito utilizado para ordenao de listas,
um exemplo prtico da aplicao desse padro.
Definir a ordem na qual determinados passos devem ser realizados na resoluo de um problema e possibilitar que eles possam ser exe-
Template Method cutados de formas diferentes de acordo com a situao. Todos os mtodos no abstratos de java.io.InputStream, java.io.OutputStream,
java.io.Reader e java.io.Writer implementam o Template Method.
Permitir que uma classe visitante mude o algoritmo de execuo de outra sem a necessidade de alter-la. Dessa forma, a execuo do al-
Visitor goritmo pode variar de acordo com a classe visitante. Um exemplo o javax.lang.model.element.ElementVisitor, que opera em conjunto
com o objeto Element do mesmo pacote.

Tabela 3. Padres de projetos comportamentais

Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia 15


Refatorando cdigo com padres de projeto

A inteno da equipe, com isso, foi isolar pequenos trechos do Listagem 2. A implementao da classe Robo.
jogo a fim de identificar, com mais facilidade, problemas que pos-
public class Robo {
sam ser sanados com boas prticas. A primeira delas, inclusive,
acabou de ser citada: dividir para conquistar. static enum MovimentoEnum {
AGRESSIVO, DEFENSIVO, ALEATORIO
}
Listagem 1. Cdigo da classe Jogo que simula o tabuleiro de batalha dos robs.
private String nome;
public class Jogo {
// Cdigo com os demais atributos suprimido
public static void main(String[] args) {
//Cria uma instncia de rob public Robo() {
Robo rambo = new Robo(); inicializar();
rambo.setNome(Rambo); }

//Cria outra instncia de rob /**
Robo chuckNorris = new Robo(); * Resgata os dados de um banco de dados para inicializar o rob.
chuckNorris.setNome(Chuck Norris); * Todos os robs so iguais, exceto o nome!
*/
//Cria mais uma instncia de rob private void inicializar() {...}
Robo bigHero = new Robo();
bigHero.setNome(Big Hero 6); public void setNome(String string) {
this.nome = nome;
//Solicita que o rob se movimente de forma agressiva }
rambo.mover(Robo.MovimentoEnum.AGRESSIVO);
//Solicita que o rob se movimente de forma defensiva /**
chuckNorris.mover(Robo.MovimentoEnum.DEFENSIVO); * Executa o comando de movimentao.
//Solicita que o rob se movimente de forma aleatria * Pode ser um ataque, uma defesa ou movimentos aleatrios!
bigHero.mover(Robo.MovimentoEnum.ALEATORIO); *
} * @param acao A ao de movimentao.
} */
public void mover(MovimentoEnum acao) {
if (MovimentoEnum.AGRESSIVO.equals(acao)) {
J na Listagem 2, temos o cdigo da classe Robo. Em seu cons- // Algoritmo para movimentao agressiva
trutor, note que h uma chamada ao mtodo inicializar(), respon- } else if (MovimentoEnum.DEFENSIVO.equals(acao)) {
// Algoritmo para movimentao defensiva
svel por acessar um banco de dados e resgatar as informaes
} else if (MovimentoEnum.ALEATORIO.equals(acao)) {
necessrias para instanciar um rob, como fora e velocidade. // O algoritmo de movimentao aleatria implementado
O mtodo mover(), por sua vez, tem a responsabilidade de realizar // por terceiros atravs do mtodo MovimentoAleatorio.execute()
new MovimentoAleatorio().execute();
a movimentao do rob. Para isso, ele recebe como parmetro
}
qual tipo de movimento o rob dever executar. Ademais, esse }
mtodo tambm possui a implementao dos algoritmos referen- }
tes ao movimento solicitado. Note que para cada movimento h Listagem 3. Classe responsvel pelo algoritmo de movimentao aleatrio do
uma lgica implementada na estrutura condicional if/else. rob.
Perceba tambm que somente a lgica de movimento aleatrio
/**
(MovimentoEnum.ALEATORIO), no mtodo mover(), apresenta * Implementao da estratgia de movimento aleatrio.
um trecho de cdigo que invoca o mtodo MovimentoAleatorio. */
public class MovimentoAleatorio {
execute(). Isso ocorre devido ao uso de uma biblioteca de terceiros
que j implementava um algoritmo de movimentao aleatria public void execute() {
para um rob. Os demais algoritmos de movimentao no foram //Algoritmo para executar a movimentao aleatria
}
analisados e por isso o cdigo dos mesmos no foi exibido.
}
A Listagem 3 apresenta o cdigo da classe MovimentoAleatorio
e como verificado, o mtodo execute() implementa o algoritmo
que realiza a movimentao aleatria de um rob. Por se tratar O primeiro problema est relacionado forma como o objeto
de uma biblioteca de terceiros, a equipe de desenvolvimento no Robo criado, pois j que os robs so todos iguais (exceto pelo
tem acesso ao cdigo fonte com a implementao real da classe. nome) e o custo para criar um rob elevado, devido necessidade
Portanto no possvel realizar modificaes. de acesso ao banco de dados, este anti-pattern pode ser resolvido
Ao analisar o cdigo das Listagens 1, 2 e 3, repare que ele possui com a aplicao do padro de projeto Prototype. Atravs desse
uma srie de anti-patterns, isto , solues para resolver problemas padro os robs podero ser clonados, em vez de ser criada uma
aplicando prticas muito utilizadas, mas que apesar de aparen- nova instncia para cada um.
temente benficas, na verdade prejudicam a manutenibilidade, Outro ponto questionvel est relacionado ao mtodo mover().
flexibilidade, reuso, entre outros. Note que ele acopla todo o conhecimento de como um rob se

16 Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia


movimenta. Desta forma, os algoritmos de movimentao ficam Ao relacionar essa estrutura com o cdigo do jogo nota-se que a
impossibilitados de serem reutilizados. Alm disso, dificulta a criao do objeto Robo (vide Listagem 2) tem um processamento
manuteno do cdigo, pois sempre que houver a necessidade muito alto para o sistema. Isso ocorre devido necessidade de
de criar um novo tipo de movimento ser necessrio adicionar acessar a base de dados sempre que um rob instanciado. Com
um if na estrutura do mtodo mover. A soluo para minimizar a implementao do Prototype o acesso base de dados ser rea-
o acoplamento e facilitar o reuso do cdigo est na aplicao do lizado somente para a criao da instncia prottipo do Robo.
Strategy, pois com ele os algoritmos de movimentao sero Portanto, a classe Robo ser refatorada para que fique com o
abstrados dentro de estratgias (classes) especficas. cdigo semelhante ao apresentado na Listagem 4. A primeira
Por fim, o padro de projeto Adapter pode ser utilizado para mudana a ser observada a implementao da interface Clo-
adaptar a classe MovimentoAleatorio em uma estratgia que ser neable. Essa interface indica que Robo ser capaz de criar uma
definida pelo padro Strategy. Lembre-se que Adapter permite cpia de si mesma. A outra mudana a implementao do m-
que estruturas diferentes possam trabalhar juntas atravs de todo clone(), que possibilita a criao de um objeto idntico ao
uma classe adaptadora e como MovimentoAleatorio pertence a objeto original.
terceiros, ela no pode ser modificada pela equipe de desenvol-
vimento do jogo.
Listagem 4. Aplicao do Prototype na classe Robo.

Aplicando o padro Prototype public class Robo implements Cloneable {


O padro de projeto Prototype tem como propsito criar novos
static enum MovimentoEnum {
objetos a partir de uma instncia prottipo, ou seja, o objeto que AGRESSIVA, DEFENSIVA, ALEATORIA
implementa esse padro capaz de criar uma cpia de si mesmo. }
Uma aplicao para esse padro pode ser verificada na manipu- private String nome;
lao de objetos com alta complexidade de serem instanciados
e que so utilizados diversas vezes, com diferentes cpias. Por public Robo() {
inicializar();
exemplo, simular diferentes modelos matemticos utilizando }
dados financeiros de um pas que, por sua vez, esto armazenados
em uma base de dados. /**
* Resgata os dados de um servidor para inicializar o rob.
Ao aplicar esse padro no necessrio carregar essas infor- * Todos os robs so iguais, exceto o nome!
maes financeiras todas as vezes que um novo modelo for */
simulado. Para isso, uma instncia prottipo pode ser criada private void inicializar() {
}
com esses dados e sempre que for preciso uma cpia dela pode
ser disponibilizada. public void setNome(String string) {
this.nome = nome;
Dito isso, esse pattern pode trazer ganhos significativos de
}
performance para uma aplicao, pois s ser necessrio executar
uma vez o processo complexo de criao desses objetos. A partir /**
* Executa o comando de movimentao.
de ento, os demais objetos sero criados atravs da cpia da
* Pode ser um ataque, uma defesa ou movimentos aleatrios!
instncia prottipo. *
A estrutura do padro Prototype pode ser vista no diagrama de * @param acao A ao de movimentao.
*/
classes exposto na Figura 1. public void mover(MovimentoEnum acao) {
if (MovimentoEnum.AGRESSIVA.equals(acao)) {
// Algoritmo para movimentao agressiva
} else if (MovimentoEnum.DEFENSIVA.equals(acao)) {
// Algoritmo para movimentao defensiva
} else if (MovimentoEnum.ALEATORIA.equals(acao)) {
// O algoritmo de movimentao aleatria implementado
// por terceiros atravs do mtodo MovimentoAleatorio.execute()
new MovimentoAleatorio().execute();
}
}

/**
* Cria e retorna a cpia do objeto Robo
*/
@Override
public Robo clone(){
return this.clone();
}
}
Figura 1. Diagrama de classe do padro Prototype Fonte: http://www.dofactory.com

Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia 17


Refatorando cdigo com padres de projeto

Aps a refatorao da classe Robo preciso atualizar o cdigo No primeiro caso, as opes para se deslocar de um lugar para
da classe Jogo para que faamos uso dos benefcios adquiridos outro podem variar de acordo com a preferncia do usurio, que
com a adoo de Prototype, como pode ser visto na Listagem 5. pode escolher fazer o caminho a p, carro ou nibus. Assim, con-
Esta alterao consiste em criar somente um objeto rob utili- forme a estratgia escolhida, o caminho para chegar ao destino
zando o operador new. Os demais robs sero criados a partir pode ser diferente.
do mtodo clone(). J para o segundo caso (a ordenao de elementos em uma lis-
ta), lembre-se que pode haver uma quantidade muito grande de
Listagem 5. Refatorao do jogo para utilizao do mtodo clone(). algoritmos de ordenao implementados e que eles podem ser
escolhidos de acordo com cada situao.
public class Jogo {
Aplicando os conceitos desse padro para soluo do problema
public static void main(String[] args) { arquitetural do mtodo mover() (vide Listagem 2), a primeira
//Cria a instncia prottipo
Robo robo = new Robo();
alterao a ser realizada criar as estratgias de movimentao
dos robs, conforme apresentado na Listagem 6.
//Cria um novo rob atravs do clone da instncia prottipo A interface MovimentoStrategy representa o artefato Strategy
Robo rambo = robo.clone();
rambo.setNome(Rambo); exposto no diagrama da Figura 1, e o mtodo executar() o res-
ponsvel pela implementao da estratgia de movimentao.
Robo chuckNorris = robo.clone();
chuckNorris.setNome(Chuck Norris);

Robo bigHero = robo.clone();


bigHero.setNome(Big Hero 6);

rambo.mover(MovimentoEnum.AGRESSIVA);
chuckNorris.mover(MovimentoEnum.DEFENSIVA);
bigHero.mover(MovimentoEnum.ALEATORIA);
}
}

Como verificado no exemplo, a utilizao desse pattern possibili-


Figura 2. Diagrama de classe Strategy Fonte: http://www.dofactory.com
tou a reduo do processamento gasto para criar objetos complexos.
Note que no ser necessrio definir uma nova instncia, utilizando
o operador new, toda vez que for preciso criar um objeto. Listagem 6. Definio da interface e implementao das classes de estratgias.

/**
Aplicando o padro Strategy * Interface que define a assinatura do mtodo a ser
O padro Strategy trata diretamente de problemas relacionados * adotado para implementao das estratgias
*/
ao acoplamento do cdigo. Ele resolve esses problemas ao definir public interface MovimentoStrategy {
uma famlia de algoritmos, encapsular cada um deles e os tornar
/**
intercambiveis. Assim, estabelecida uma separao dos algo- * Execuo da movimentao definida pela estratgia.
ritmos de quem os usa, separao esta que possibilita escolher */
public void executar();
qual algoritmo utilizar de forma dinmica. Por exemplo, a opo }
de gravar informaes em um banco de dados ou em disco rgido
pode variar de acordo com a disponibilidade de espao. /**
* Implementao da estratgia de movimento agressivo.
Portanto, a abordagem proposta na definio do Strategy aco- */
plar a classe que far uso dos algoritmos apenas a uma abstrao e public class MovimentoAgressivo implements MovimentoStrategy{

no a uma implementao. Com isso, o cdigo fica menos acoplado @Override


devido possibilidade de ele utilizar diferentes estratgias sem public void executar() {
//Algoritmo para movimentao agressiva
conhecer como elas so implementadas. }
O diagrama da Figura 2 ilustra a organizao desse padro. }
De acordo com essa figura, a interface que representa a abstrao
/**
da coleo de algoritmos a Strategy. Ela responsvel por definir * Implementao da estratgia de movimento defensivo.
a assinatura do mtodo a ser implementado pelas classes concretas */
public class MovimentoDefensivo implements MovimentoStrategy{
(ConcreteStrategyA, ConcreteStrategyB e ConcreteStrategyC).
J a classe Context a classe que faz uso, de forma transparente, @Override
public void executar() {
das estratgias implementadas nas classes concretas. //Algoritmo para movimentao defensiva
Dois timos exemplos da aplicao desse padro de projeto }
}
so o Google Maps e a ordenao de elementos em uma lista.

18 Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia


J as classes MovimentoAgressivo e MovimentoDefensivo cor- do como Wrapper, esse design pattern permite que classes com
respondem implementao concreta desses algoritmos. estruturas diferentes possam trabalhar em conjunto atravs da
Essas estratgias, tambm expostas na ltima listagem referen- adequao da interface incompatvel.
ciada, sero utilizadas para desacoplar o cdigo do mtodo mo- O diagrama apresentado na Figura 3 exibe a estrutura desse
ver(). Assim, a lgica condicional ser removida e a movimentao padro. Nele est presente a interface Target, que define a interface
do rob passar a ser executada conforme a estratgia enviada compatvel para ser usada pela classe Client, e tambm a classe
como parmetro para esse mtodo (vide Listagem 7). Adapter, responsvel por encapsular e adaptar a Adaptee para
A partir disso, caso haja a necessidade de implementar uma que esta possa ser utilizada pelo Client, visto que sua interface
nova ao de movimento, a classe Robo no precisar sofrer incompatvel com a estrutura requerida pela classe cliente.
alteraes, j que ela est acoplada apenas a uma abstrao. Ou Um exemplo desse padro no mundo real pode ser encontrado
seja, ser necessrio apenas criar uma classe que implemente a nos adaptadores feitos para que os cartes de memria das m-
interface MovimentoStrategy e pass-la para o mtodo mover() quinas fotogrficas digitais sejam utilizados nos laptops. Outro
como parmetro. exemplo interessante so as tomadas de energia. No Brasil, por
Assim como realizado anteriormente, aps a refatorao na clas- exemplo, haviam vrios modelos de tomadas e plugues antes
se Robo preciso alterar mais uma vez a classe Jogo. Conforme
a Listagem 8, a mudana foi feita para enviar ao mtodo mover()
a instncia da estratgia de movimento do rob.

Listagem 7. Refatorao do mtodo mover().

public class Robo implements Cloneable {

//Cdigo suprimido...

/**
* Executa o comando de movimentao, sem ter o conhecimento
* de sua implementao.
*/
public void mover(MovimentoStrategy movimento) {
//Faz alguma coisa
movimento.executar();
//Faz mais alguma coisa Figura 3. Diagrama do padro Adapter Fonte: http://www.dofactory.com
}

/** Listagem 8. Refatorao para adequar a chamada ao mtodo mover com as
* Cria e retorna a cpia do objeto Robo estratgias.
*/
@Override public class Jogo {
protected Robo clone(){
return this.clone(); public static void main(String[] args) {
} //Cria a instncia prottipo
} Robo robo = new Robo();

//Cria um novo rob atravs do clone da instncia prottipo


Robo rambo = robo.clone();
Observe que aps a implementao do padro Strategy foi rambo.setNome(Rambo);

possvel isolar os algoritmos de movimento do rob em classes Robo chuckNorris = robo.clone();
separadas, facilitando a manuteno e desacoplando o cdigo. chuckNorris.setNome(Chuck Norris);
Alm disso, o padro permite que as mesmas estratgias sejam
Robo bigHero = robo.clone();
reusadas em outros locais. bigHero.setNome(Big Hero 6);
Porm, com essa refatorao o jogo ficou sem a possibilidade
/**
de uso do movimento aleatrio, fornecido pela classe Movimen- * O mtodo mover() agora recebe a estratgia de movimentao,
toAleatorio. Isso ocorreu porque essa classe no implementa a * ao invs de necessitar implementar o movimento.
*/
interface MovimentoStrategy, e como se trata de uma classe de rambo.mover(new MovimentoAgressivo());
terceiros no possvel refator-la. Para conseguir que o jogo chuckNorris.mover(new MovimentoDefensivo());

tenha as mesmas possibilidades de movimentao, o padro
/**
Adapter ser adotado. * Cdigo parou de compilar, pois a classe MovimentoAleatorio
* no implementa a interface MovimentoStrategy
*/
Aplicando o padro Adapter bigHero.mover(new MovimentoAleatorio());
exatamente para atender a necessidade de adaptar coisas que }
}
o padro estrutural Adapter deve ser aplicado. Tambm conheci-

Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia 19


Refatorando cdigo com padres de projeto

da padronizao realizada pela ABNT. Aps a padronizao, os Listagem 10. Classe com a refatorao para adaptar o movimento aleatrio.
produtos devem ter somente os plugues com a nova forma de trs
public class Jogo {
pinos redondos. Porm, muitas residncias no possuem tomadas
de trs pinos para receber os aparelhos com esse tipo de plugue public static void main(String[] args) {
e para isso necessrio um adaptador. //Cria a instncia prottipo
Robo robo = new Robo();
J um exemplo no desenvolvimento de software pode ser
demonstrado no nosso jogo de robs. Lembra que a adoo do //Cria um novo rob atravs do clone da instncia prottipo
Robo rambo = robo.clone();
padro Strategy impossibilitou o uso da classe MovimentoAle- rambo.setNome(Rambo);
atorio? A aplicao do Adapter pode solucionar esse problema.
Robo chuckNorris = robo.clone();
Correlacionando os artefatos desse padro ao nosso exemplo, a chuckNorris.setNome(Chuck Norris);
interface MovimentoStrategy corresponde Target, e a classe
MovimentoAleatorio corresponde Adaptee. Para completar, Robo bigHero = robo.clone();
bigHero.setNome(Big Hero 6);
necessrio implementar a classe que far a adaptao de Mo-
vimentoAleatorio para ser utilizada junto s outras estratgias /**
* O mtodo mover agora recebe a estratgia de movimentao,
definidas pelo padro Strategy. * ao invs de necessitar implementar o movimento.
Para isso, criamos a classe MovimentoAleatorioAdaptado, */
rambo.mover(new MovimentoAgressivo());
apresentada na Listagem 9. Ela deve implementar a interface chuckNorris.mover(new MovimentoDefensivo());
MovimentoStrategy e encapsular MovimentoAleatorio. Assim o
jogo poder fazer uso do movimento fornecido por essa classe. /**
* A classe de movimento aleatrio agora est adaptada
* interface MovimentoStrategy, permitindo o seu uso
Listagem 9. Classe para adaptar MovimentoAleatorio. * no mtodo de movimentao do rob.
*/
/** bigHero.mover(new MovimentoAleatorioAdaptado());
* Adaptador para encapsular a classe de movimento aleatrio }
* em uma estratgia }
*/
public class MovimentoAleatorioAdaptado implements MovimentoStrategy{
Eles podem ser aplicados em situaes do cotidiano, como de-
private MovimentoAleatorio comportamento;
monstrado no artigo. E em sistemas computacionais, saiba que eles
@Override no foram especificados para serem aplicados em uma linguagem
public void executar() {
comportamento.execute();
de programao especfica. Uma prova disso que no livro de
} referncia do GoF os exemplos so ilustrados em C++.
}

Autor
Por fim, a classe Jogo (vide Listagem 10) precisa ser refatorada
Gabriel Feitosa
mais uma vez para que faa uso da nova classe Movimento- gabfeitosa@gmail.com www.gabrielfeitosa.com
AleatorioAdaptado. Pronto! Com isso, todas as estratgias de Bacharel em Cincia da Computao pela Universidade Federal
movimentao voltam a ser utilizadas. de Campina Grande (UFCG), Ps-Graduando em Engenharia de
Escrever cdigo de qualidade depende de fatores como experi- Software na Faculdade 7 de Setembro (FA7), engenheiro de software,
ncia da equipe de desenvolvimento e da aplicao de conceitos j desenvolve aplicando conceitos como TDD e reviso em pares, especialista
difundidos, como o caso dos padres de projetos. Como prova em Java e em aplicaes que utilizam o conceito de Single-Page Application (SPA).
disso, a refatorao que foi realizada no cdigo do jogo resultou
em um cdigo menos acoplado, mais coeso e possibilitou a reduo Links e Livros:
no processamento para se criar objetos complexos.
Alm disso, ficou muito mais simples criar novas possibilidades de Exemplos prticos de padres de projetos com foco na plataforma Java. http://
movimentao para o rob e de test-las. Isso ocorreu devido ao iso- www.tutorialspoint.com/design_pattern/index.htm
lamento dos algoritmos de movimentao em classes separadas. Coletnea de exemplos prticos com UML de padres de projetos aplicados
Ainda que padres de projeto sejam solues abstratas para a linguagem Java.
resoluo de determinados problemas, eles so uma referncia http://www.oodesign.com/
que auxilia o profissional a produzir cdigo de melhor qualidade. Design Patterns: Elements of Reusable Object-Oriented Software, Erich Gamma,
Ademais, eles propiciam uma linguagem de comunicao comum Richard Helm, Ralph Johnson, John Vlissides, Addison-Wesley, 1995.
a ser utilizada pelos desenvolvedores para debater a resoluo de Livro de referncia quando o assunto padres de projeto.
problemas na construo de sistemas computacionais. Head First Design Patterns, Eric Freeman, Elisabeth Robson, Bert Bates, Kathy
Lembre-se que os padres de projeto no foram definidos apenas Sierra, 2004.
para serem utilizados no mbito computacional. Livro que exemplifica os padres usando comparaes com o mundo real.

20 Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia


Aprenda a utilizar o Spring
Web Flow
Saiba como implementar fluxos de navegao
em uma aplicao Web com um exemplo usando
Spring e Hibernate

F Fique por dentro


rameworks Model-View-Controller so vastamen-
te utilizados e seus benefcios so amplamente
conhecidos. Por exemplo, a forma como o padro Apresentaremos neste artigo o desenvolvimento de um projeto web
MVC distribui responsabilidades nas camadas da que adota o padro Model-View-Controller com o Spring Web Flow
aplicao faz com que tenhamos camadas mais magras (SWF), parte do framework Spring MVC destinada implementao
e, consequentemente, cdigo mais organizado e manu- de fluxos de navegao em aplicaes web. O SWF ser utilizado
teno mais simples. No Struts vemos isso ilustrado na para tornar possvel a definio de sequncias de passos que guiam
medida em que escrevemos cdigo Java em actions, ao o usurio pelas pginas do website com pouca escrita de cdigo Java,
invs de manter grandes parte da lgica do negcio em de forma reusvel e de fcil manuteno. Deste modo, esse artigo
pginas JSP. importante tambm por demonstrar como o SWF integrado ao
No entanto, uma das principais vantagens da maioria Spring MVC, bem como ao Hibernate ORM na construo de uma
dos frameworks MVC no to visvel: a possibilidade aplicao web completa.
de definir fluxos de navegao, ou seja, descrever con-
juntos de passos para os usurios no website de forma
estruturada e reusvel. Neste cenrio, o Struts e o Spring, constantemente verificar o cdigo para entender os fluxos, espe-
por exemplo, encapsulam os detalhes a respeito do aten- cialmente aqueles que envolvem condies e mltiplos estados.
dimento das requisies de um usurio e renderizam Ademais, a manuteno de grandes sites pode ser complicada e
pginas de resposta por meio da configurao de actions envolver bastante tempo estudando seus fluxos antes de imple-
(ou handlers) de acordo com o estado da requisio. Isso mentar uma modificao.
pode ser notado quando temos a exibio de uma pgina Com base nisso, neste artigo vamos explorar uma soluo
de erro ou de sucesso dependendo da ao realizada dada pelo Spring para o gerenciamento do fluxo de navegao
pelo usurio. em websites: o Spring Web Flow. Iniciado como uma extenso
Fluxos simples como o do exemplo citado so per- do Spring Framework, sua primeira verso estvel foi lanada
feitamente gerenciveis pelos mecanismos nativos da em 2006, no entanto, sua popularizao ocorreu apenas com a
maioria dos frameworks MVC. Contudo, na medida em verso 2, lanada em 2008.
que a aplicao web se torna maior, com mais pginas ou Com o SWF o fluxo de navegao construdo por meio da defi-
com mais opes de respostas para as aes disponveis, nio dos estados pelos quais o usurio passa. A partir disso, para
gerenciar esses fluxos pode se tornar mais complicado, chegar em cada um dos estados o usurio dispara eventos. Por
uma vez que os frameworks MVC mais conhecidos sua vez, entre os eventos que fazem as passagens de um estado
no gerenciam os estados das requisies (vide BOX 1),
tornando necessrio escrever mais cdigo nos handlers BOX 1. Estado das requisies em aplicaes web
para fazer esse trabalho.
Numa aplicao web cada estado de uma requisio representa um propsito especfico e, por isso,
Outro aspecto interessante sobre o gerenciamento do
ter uma pgina ou handler correspondente. Por exemplo, a submisso de uma pgina de formulrio
fluxo de navegao que, se a estrutura da aplicao
pode ter quatro ou mais estados possveis, a saber: o estado inicial (a exibio do formulrio em si);
complexa, ou seja, se os caminhos para chegar s
aguardando (quando o formulrio est sendo submetido, aps o clique no boto de submisso);
pginas so longos e/ou muito subdivididos, enten- sucesso (que resultar na exibio de uma pgina de sucesso); ou insucesso (que resultar na
der o fluxo se torna mais difcil. Nesses casos, seria exibio de uma pgina de erro).
necessrio manter um mapa atualizado das pginas e

Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia 21


Aprenda a utilizar o Spring Web Flow

para outro temos as transies de estado. Todo esse mecanismo


especificado em regras dentro de um arquivo XML, o que viabiliza
o reuso e diminui a escrita de cdigo.
No exemplo que apresentaremos nesse artigo focaremos nas
principais vantagens do SWF ilustrando as maiores contribui-
es dadas por esse projeto ao desenvolvimento web, alm de
demonstrar seu uso de forma integrada com o Spring MVC e
Hibernate. Dessa forma, nosso exemplo ficar bastante completo
e fornecer ao leitor todos os passos necessrios para iniciar o
desenvolvimento com os frameworks citados, assim como algu-
mas noes sobre padres arquiteturais bastante utilizados em
solues dessa natureza.

Detalhes do projeto exemplo


O projeto ser construdo com a IDE Eclipse, persistir dados em
um banco de dados MySQL, rodar no Tomcat 8 e sua implemen-
tao seguir o padro Model-View-Controller, com o suporte do
Spring MVC 4.2.2. A arquitetura da aplicao inclui ainda uma
Figura 1. Janela de seleo de tipo de projeto no Eclipse
camada de servio rudimentar, responsvel por fazer a ligao
entre a camada de controle e a camada de dados usando uma
simplificao do padro Service Layer.
A camada de persistncia seguir o padro DAO e utilizaremos
o framework Hibernate ORM 4.3.11 para implement-la. J a
nossa verso do SWF ser a 2.4.0. Alm disso, sugerimos o uso
do Eclipse em verso superior 4.4 (Luna, para desenvolvimento
Java EE) por j possuir integrao nativa com o gerenciador de
dependncias Maven. Caso essa no seja a sua verso do Eclipse,
necessrio instalar o Maven em verso igual ou superior 3.2
(e/ou um plugin respectivo do Maven para Eclipse) ou gerenciar
as dependncias do projeto manualmente.
Sendo assim, mais do que demonstrar o uso do SWF, apresen-
taremos um exemplo completo da integrao entre Spring Web
Flow, Spring MVC e Hibernate. No entanto, importante destacar
que no objetivo desse artigo discorrer sobre as arquiteturas
e padres de projeto, bem como sobre os frameworks Spring e
Hibernate. Dessa forma, o leitor deve explorar a documentao
correspondente ou artigos anteriores publicados nessa revista
sobre o uso desses recursos.

Criando o projeto e configurando as dependncias


Primeiramente, criemos um Dynamic Web Project no Eclipse,
o qual chamaremos de GestaoAcademicaWeb. Para isso, aps
acessar as opes de menu File > New Project > Other, na janela
New Project, selecione Web > Dynamic Web Project, conforme a
Figura 1.
Clicando em Next ser exibida a janela com as propriedades Figura 2. Janela de propriedades do projeto
do projeto (vide Figura 2). Vamos configur-lo para rodar no
container Tomcat 8, no entanto, o leitor deve ficar vontade para mostra a Figura 3. Ser criado, assim, o arquivo pom.xml, onde
utilizar verses diferentes do Tomcat ou outro container web Java, vamos inserir as dependncias do nosso projeto, conforme des-
como Jetty ou JBoss. Feito isso, clique em Finish. crito na Listagem 1.
Com o projeto criado, vamos integr-lo ao gerenciador de de- Repare que inclumos nesse arquivo todas as dependncias
pendncias Maven. Portanto, clique com o boto direito sobre necessrias para utilizar o Spring MVC e o Hibernate ORM,
o projeto e selecione Configure > Convert to Maven Project, como assim como o driver JDBC solicitado para a conexo com o banco

22 Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia


de dados. Em seguida, devemos criar tambm os arquivos \src\ configuraes que o Hibernate usa para acessar o banco de dados
hibernate.cfg.xml e spring-context.xml, que encapsulam as confi- como, por exemplo, o datasource.
guraes do Hibernate e do Spring MVC e cujos cdigos-fontes Agora, vamos definir o arquivo \WEB-INF\jdbc.properties para
podem ser vistos junto ao cdigo disponvel para download na armazenar as configuraes de acesso ao banco, como URI, usu-
pgina desta edio. rio e senha (vide Listagem 2). As propriedades contidas nesse
Em hibernate.cfg.xml sero feitas as configuraes corresponden- arquivo so, ento, chamadas em spring-context.xml.
tes ao mapeamento objeto-relacional (Vide BOX 2), como veremos
BOX 2. Mapeamento Objeto-Relacional
ao longo do artigo. J o arquivo spring-context.xml inclui as con-
figuraes do Spring, como o diretrio em que as pginas da ca- Mapeamento Objeto-Relacional a tcnica utilizada para tornar possvel a representao das
mada de viso sero armazenadas e, futuramente, configuraes classes da aplicao projetadas a partir do paradigma da Orientao a Objetos em entidades de
do SWF. Tambm aproveitamos esse arquivo para armazenar as um banco de dados relacional projetadas a partir do paradigma Relacional e da Normalizao.

Listagem 1. Cdigo-fonte do arquivo pom.xml.

<project xmlns=http://maven.apache.org/POM/4.0.0 xmlns:xsi=http://www. <version>4.2.2.RELEASE</version>


w3.org/2001/XMLSchema-instance xsi:schemaLocation=http://maven.apache.org/ </dependency>
POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd> <dependency>
<modelVersion>4.0.0</modelVersion> <groupId>org.springframework</groupId>
<groupId>GestaoAcademicaWeb</groupId> <artifactId>spring-tx</artifactId>
<artifactId>GestaoAcademicaWeb</artifactId> <version>4.2.2.RELEASE</version>
<version>0.0.1-SNAPSHOT</version> </dependency>
<packaging>war</packaging> <dependency>
<build> <groupId>org.springframework</groupId>
<sourceDirectory>src</sourceDirectory> <artifactId>spring-webmvc</artifactId>
<resources> <version>4.2.2.RELEASE</version>
<resource> </dependency>
<directory>src</directory> <dependency>
<excludes> <groupId>org.springframework</groupId>
<exclude>**/*.java</exclude> <artifactId>spring-orm</artifactId>
</excludes> <version>4.2.2.RELEASE</version>
</resource> </dependency>
</resources> <dependency>
<plugins> <groupId>org.springframework.webflow</groupId>
<plugin> <artifactId>spring-webflow</artifactId>
<artifactId>maven-compiler-plugin</artifactId> <version>2.4.0.RELEASE</version>
<version>3.1</version> </dependency>
<configuration> <dependency>
<source>1.7</source> <groupId>org.hibernate</groupId>
<target>1.7</target> <artifactId>hibernate-core</artifactId>
</configuration> <version>4.3.11.Final</version>
</plugin> <scope>compile</scope>
<plugin> </dependency>
<artifactId>maven-war-plugin</artifactId> <dependency>
<version>2.4</version> <groupId>jstl</groupId>
<configuration> <artifactId>jstl</artifactId>
<warSourceDirectory>WebContent</warSourceDirectory> <version>1.2</version>
<failOnMissingWebXml>false</failOnMissingWebXml> </dependency>
</configuration> <dependency>
</plugin> <groupId>commons-dbcp</groupId>
</plugins> <artifactId>commons-dbcp</artifactId>
</build> <version>1.4</version>
<dependencies> </dependency>
<dependency> <dependency>
<groupId>org.springframework</groupId> <groupId>mysql</groupId>
<artifactId>spring-context</artifactId> <artifactId>mysql-connector-java</artifactId>
<version>4.2.2.RELEASE</version> <version>5.1.6</version>
</dependency> </dependency>
<dependency> </dependencies>
<groupId>org.springframework</groupId> </project>
<artifactId>spring-web</artifactId>

Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia 23


Aprenda a utilizar o Spring Web Flow

Figura 4. Criando o pacote-base da aplicao

Figura 3. Convertendo o projeto para Maven

Neste ponto vale ressaltar que, embora no seja necessrio seguir a


ordem de criao dos arquivos sugerida nesse artigo, os passos que
demonstramos simplificam o desenvolvimento, j que vemos que
os arquivos fazem referncias uns aos outros em alguns casos.
O prximo passo criar a estrutura do projeto de acordo com os Figura 5. Estrutura do projeto
padres que sero adotados; no nosso caso, uma arquitetura MVC,
uma camada de servio, alm do padro DAO para a camada de
persistncia. Sendo assim, clique com o boto direito sobre a pasta Listagem 2. Cdigo do arquivo jdbc.properties.
Java Resources\src, no Package Explorer do Eclipse, e selecione New >
jdbc.driverClassName= com.mysql.jdbc.Driver
Package para criar o pacote-base do projeto. Conforme demonstra
jdbc.dialect=org.hibernate.dialect.MySQLDialect
a Figura 4, digite br.com.devmedia.gestaoacademicaweb no jdbc.databaseurl=jdbc:mysql://localhost:3306/gestaoacademica
campo Name e clique em Finish. jdbc.username=gestaoacademica
jdbc.password=gestaoacademica
Dentro do pacote-base vamos repetir o mesmo procedimento
para criar os pacotes control e model, alm do dao onde sero
armazenadas as classes da camada de persistncia da nossa apli- View-state: representado por uma pgina na qual o usurio
cao e service onde ficaro as classes da camada de servio. chega espontaneamente, por exemplo, digitando um endereo;
Nossas pginas (a camada view) ficaro no diretrio WEB-INF/ End-state: representado por uma pgina na qual o usurio chega
views. Por fim, criaremos, tambm, o diretrio WEB-INF/flows, como resultado de um evento, como clicar em um link ou como
onde armazenaremos os fluxos. Dessa forma, a estrutura do resposta a uma submisso de formulrio.
projeto deve ficar como mostrado na Figura 5.
Mais alm, os handlers responsveis pelas submisses de for-
O fluxo da aplicao exemplo mulrios so representados como um sub-estado chamado
Para comear, lembremos que, com SWF, um fluxo composto action-state, que existe entre view-state e um end-state.
por um conjunto de estados, cada estado ter uma pgina corres- Como nesse artigo criaremos um cadastro de docentes de uma
pondente e as mudanas de estado e, consequentemente, de pgi- universidade cujo fluxo bastante simples, especificamos apenas
na, ocorrem aps o usurio disparar eventos. A partir disso, saiba trs estados (dois view-states e um end-state), como segue:
que esses eventos podem levar a dois tipos bsicos de estado: 1. View-state 1, representado pela pgina de listagem;

24 Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia


2. View-state 2, representado pelo formulrio de cadastro de do pelas camadas de modelo e persistncia e depois pelas camadas
docentes; de servio e controle. Na sequncia, construiremos o fluxo com o
3. End-state, representado pela pgina de resposta ao cancelamento. SWF, objeto principal desse artigo.

A Figura 6 demonstra o fluxo do nosso projeto exemplo, ilus- As camadas de modelo e persistncia
trando seus estados e transies. Vamos iniciar a nossa implementao criando, dentro do pacote
model, a classe Docente, nico JavaBean do nosso projeto. Sen-
do assim, com o boto direito sobre o pacote, selecione a opo
New > Class. Em seguida, digite o nome Docente e clique em Finish.
O cdigo-fonte desse artefato pode ser visto na Listagem 3. Nele,
podemos observar anotaes (vide BOX 3) do Hibernate que asso-
ciam esta classe/entidade sua respectiva tabela no banco de dados
(atravs da anotao @Table). Como podemos observar tambm, cada
atributo da classe associado a um campo em sua respectiva tabela,
por meio da anotao @Column. Finalizando, vamos configurar o
mapeamento objeto-relacional de Docente no arquivo hibernate.cfg
.xml, para habilitar o Hibernate a persistir os objetos no banco de
dados, o que pode ser feito com o cdigo da Listagem 4.

BOX 3. Anotaes

Anotaes so recursos para a declarao de metadados dados que descrevem outros dados
teis para localizar dependncias, configuraes ou para fazer verificaes lgicas. Essas definies
sero, ento, interpretadas pelo compilador para realizar uma determinada tarefa.

Com o JavaBean da camada de modelo criado, podemos imple-


mentar a camada de persistncia, que consiste em uma interface
(DocenteDAO) e sua implementao (DocenteDAOImpl).
A interface DocenteDAO declara os mtodos para inserir e excluir
registros do tipo Docente no banco de dados (adicionarDocente() e
removerDocente(), respectivamente), bem como para recuper-los
em uma operao de listagem (listarDocentes()). Como a classe
DocenteDAOImpl implementa a interface DocenteDAO, vemos em
Figura 6. Representao do fluxo de nosso projeto-exemplo seu corpo a implementao dos mtodos que realizam as operaes
com o banco de dados. Nesses mtodos o Hibernate chamado
Podemos ver que entre os estados temos as transies novo, para realizar as operaes de insero (por meio do mtodo save()),
excluir, cancelar e inserir. Isso significa que da pgina ini- excluso (com o mtodo delete()), e listagem (atravs do mtodo
cial a listagem de docentes temos eventos que levam o usurio list()), como mostra o cdigo-fonte visto nas Listagens 5 e 6.
para incluir novo docente ou excluir docentes, ambos por meio de
cliques em links. Se escolher incluir um docente, o usurio ser As camadas de servio e controle
direcionado para o formulrio de cadastro. E se escolher excluir Aps implementarmos o modelo e a persistncia vamos codificar
um docente, o usurio mantido na pgina com a listagem de uma pequena camada de servio para fazer com que a aplicao
docentes aps a operao. fique magra e possibilite que as regras de negcio sejam en-
Uma vez na pgina do formulrio de docentes o usurio pode capsuladas em camadas mais simples e reusveis. Isso ocorre na
optar por inserir o docente ou cancelar a operao. Se optar por medida em que os servios assumem a responsabilidade de fazer
inserir, aps a operao de cadastro ser realizada com sucesso o as chamadas camada de persistncia, deixando assim a lgica
usurio direcionado de volta listagem. Se escolher cancelar, de negcio encapsulada nos controllers.
direcionado para uma pgina de resposta. No nosso exemplo implementaremos a camada de servio com
uma simplificao do padro Service Layer (BOX 4). Para isso, crie
Implementao do projeto exemplo dois arquivos no pacote br.com.devmedia.gestaoacademicaweb.
Nas sees anteriores descrevemos todos os conceitos necess- service: a interface DocenteService e sua implementao, a classe
rios construo do nosso projeto com o SWF. A partir de agora, DocenteServiceImpl. Vemos, ento, nos mtodos adicionarDo-
partiremos para a implementao da aplicao exemplo, comean- cente(), removerDocente() e listar(), chamadas s respectivas

Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia 25


Aprenda a utilizar o Spring Web Flow

Listagem 3. Cdigo-fonte da classe Docente. operaes na camada de persistncia, como demonstram as


Listagens 7 e 8, e vemos tambm que a classe declarada com
package br.com.devmedia.gestaoacademicaweb.model;
@Service, anotao do Spring utilizada para descrev-la como
import javax.persistence.Column; parte da camada de servio da aplicao.
import javax.persistence.Entity; Por sua vez, os dados a serem persistidos devem ser recebidos
import javax.persistence.GeneratedValue;
import javax.persistence.Id; na camada de controle, responsvel por dar o tratamento cor-
import javax.persistence.Table; respondente s requisies de acordo com as regras de negcio
definidas. Vamos ento criar a camada de controle no pacote
@Entity
@Table(name=DOCENTES) control, comeando pela classe DocenteController, cujo cdigo
public class Docente { pode ser visto na Listagem 9.
@Id BOX 4. Padro Service Layer
@Column(name=ID)
@GeneratedValue Service Layer um padro de projeto orientado a objetos que visa organizar a lgica de negcio
private Integer id;

em servios que, devidamente categorizados, compartilham funcionalidades. Dessa forma, o
@Column(name=NOME) esforo conceitual de manuteno e gerenciamento destas reduzido, uma vez que os mdulos da
private String nome; aplicao passam a compartilhar funcionalidades comuns encapsuladas nos servios.

@Column(name=MATRICULA)
private String matricula;
Listagem 5. Cdigo-fonte da interface DocenteDAO.
@Column(name=TITULACAO)
private String titulacao; package br.com.devmedia.gestaoacademicaweb.dao;

public Integer getId() { import java.util.List;
return id; import br.com.devmedia.gestaoacademicaweb.model.Docente;
}
public void setId(Integer id) { public interface DocenteDAO {
this.id = id; public void adicionarDocente(Docente docente);
} public void removerDocente(int id);
public String getNome() { public List<Docente> listarDocentes();
return nome; }
}
public void setNome(String nome) { Listagem 6. Cdigo-fonte da classe DocenteDAOImpl.
this.nome = nome;
} package br.com.devmedia.gestaoacademicaweb.dao;
public String getMatricula() {
return matricula; import java.util.List;
} import br.com.devmedia.gestaoacademicaweb.model.Docente;
public void setMatricula(String matricula) { import org.hibernate.SessionFactory;
this.matricula = matricula; import org.springframework.beans.factory.annotation.Autowired;
} import org.springframework.stereotype.Repository;
public String getTitulacao() {
return titulacao; @Repository
} public class DocenteDAOImpl implements DocenteDAO {
public void setTitulacao(String titulacao) {
this.titulacao = titulacao; @Autowired
} private SessionFactory sessionFactory;

} public void adicionarDocente(Docente docente) {
sessionFactory.getCurrentSession().save(docente);
Listagem 4 . Cdigo-fonte do arquivo hibernate.cfg.xml, incluindo o mapeamento }
objeto-relacional da classe Docente.
public void removerDocente(int id) {
<?xml version=1.0 encoding=utf-8?> Docente docente = (Docente) sessionFactory.getCurrentSession()
<!DOCTYPE hibernate-configuration PUBLIC .load(Docente.class, id);
-//Hibernate/Hibernate Configuration DTD//EN if (null != docente) {
http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd> sessionFactory.getCurrentSession().delete(docente);
}
<hibernate-configuration> }
<session-factory>
</session-factory> public List<Docente> listarDocentes() {
return sessionFactory.getCurrentSession().createQuery(from Docente).list();
</hibernate-configuration> }
<mapping class=br.com.devmedia.gestaoacademicaweb.model.Docente />
</session-factory> }
</hibernate-configuration> }

26 Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia


Listagem 7. Cdigo-fonte da interface DocenteService. Observe nessa listagem que os mtodos acessam a camada de
servio para realizar as operaes com o banco de dados, como
package br.com.devmedia.gestaoacademicaweb.service;
mostra a instruo docenteService.adicionarDocente(docente).
import java.util.List;

import br.com.devmedia.gestaoacademicaweb.Docente;
Implementando o fluxo com o Spring Web Flow
Com as camadas de modelo, controle, servio e persistncia con-
public interface DocenteService { cludas, j possvel implementar o fluxo da aplicao, bem como
public void adicionarDocente(Docente docente);
public void removerDocente(int id); a camada de viso, que conter as pginas que correspondero
public List<Docente> listarDocentes(); aos estados declarados no fluxo.
}
Para manter o cdigo estruturado alm de permitir um even-
Listagem 8. Cdigo-fonte da implementao do servio DocenteServiceImpl. tual reuso dos fluxos criados recomendamos a criao de um
arquivo XML para cada fluxo da aplicao. No nosso caso arma-
package br.com.devmedia.gestaoacademicaweb.service;
zenaremos estes arquivos XML dentro de WEB-INF/flows.
import java.util.List; Dito isso, dentro do diretrio flows crie o arquivo inserirDocente
import br.com.devmedia.gestaoacademicaweb.Docente;
import br.com.devmedia.gestaoacademicaweb.dao.DocenteDAO;
.xml, o que feito clicando com o boto direito sobre este diretrio
import org.springframework.beans.factory.annotation.Autowired; e selecionando New > File. Uma vez que necessrio realizar as
import org.springframework.stereotype.Service; configuraes correspondentes ao SWF no arquivo spring-context.
import org.springframework.transaction.annotation.Transactional;
xml, ainda no alteraremos o XML recm-criado. Vamos, agora,
@Service modificar as configuraes do Spring alterando seu arquivo de con-
public class DocenteServiceImpl implements DocenteService {
figurao para que fique conforme demonstrado na Listagem 10.
@Autowired As principais modificaes que fizemos em spring-context.
private DocenteDAO docenteDAO;

xml para configurar o SWF se referem ao mapeamento dos
@Transactional fluxos que nosso website possui. No nosso caso chamamos o
public void adicionarDocente(Docente docente) {
fluxo de inserirDocente. Podemos verificar sua descrio no n
docenteDAO.adicionarDocente(docente);
} <webflow:flow-registry>, onde h a declarao <webflow:flow-
@Transactional location path=/W EB -I N F / f lows / inse r irDoc e nte. x ml
public void removerDocente(int id) {
docenteDAO.removerDocente(id); id=inserirDocente />, que especifica que o fluxo identificado
} por inserirDocente est declarado no arquivo de mesmo nome,
@Transactional com extenso XML, localizado em /WEB-INF/flows/.
public List<Docente> listarDocentes() { Seguindo em frente, declaramos os controllers da nossa aplica-
return docenteDAO.listarDocentes();
}
o utilizando a tag <bean>, como verificado no trecho <bean
name=docenteController class=br.com.devmedia.gestaoaca-
} demicaweb.control.DocenteController />. Vale lembrar que no
Listagem 9. Cdigo-fonte da classe DocenteController. nosso exemplo temos apenas um controller, que ser identificado
pelo nome docenteController.
package br.com.devmedia.gestaoacademicaweb.control;
No mais, foram includas em spring-context.xml as configuraes
import java.util.*; padro do SWF, especialmente das classes FlowHandlerMapping
import org.springframework.beans.factory.annotation.Autowired;
e FlowHandlerAdapter, os chamados flow handlers do Spring
import org.springframework.stereotype.Controller;
import br.com.devmedia.gestaoacademicaweb.model.Docente; Web Flow.
import br.com.devmedia.gestaoacademicaweb.service.DocenteService;

@Controller Desenvolvendo as pginas da camada de viso


public class DocenteController { Antes de iniciar o desenvolvimento do fluxo, vamos criar as
@Autowired
pginas da nossa camada de viso: um formulrio para cadastro
private DocenteService docenteService; de Docentes (inserir_docente_form.jsp); uma pgina que exibir uma
lista dos docentes cadastrados (listar_docente.jsp); e a pgina de
public List<Docente> listarDocentes() {
List<Docente> docentes = docenteService.listarDocentes(); resposta ao cancelamento (cancelado.jsp). Todas sero armazenadas
return docentes; no diretrio WEB-INF/views.
}
Dito isso, com o boto direito sobre o diretrio WEB-INF/views,
public void adicionarDocente(Docente docente) { selecione New > JSP File. Na janela de propriedades do arquivo,
docenteService.adicionarDocente(docente);
} digite no campo File Name o nome inserir_docente_form.jsp e
public void removerDocente(int id) { clique em Finish. O cdigo-fonte do formulrio de cadastro de
docenteService.removerDocente(id);
}
docentes pode ser visto na Listagem 11, enquanto possvel
} visualizar sua aparncia na Figura 7.

Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia 27


Aprenda a utilizar o Spring Web Flow

Listagem 10. Cdigo-fonte do arquivo spring-context.xml, incluindo as configu- Listagem 11. Cdigo-fonte do formulrio de cadastro de docentes.
raes do SWF.
<%@taglib uri=http://www.springframework.org/tags prefix=spring%>
<?xml version=1.0 encoding=UTF-8?> <%@taglib uri=http://www.springframework.org/tags/form prefix=form%>
... <html>
<context:annotation-config /> <head>
<context:component-scan base-package=br.com.devmedia.gestaoacademicaweb /> <title>Cadastro de Docentes</title>
</head>
<body>
<bean id=jspViewResolver
class=org.springframework.web.servlet.view.InternalResourceViewResolver>
<h3>Formulrio de Cadastro de Docentes</h3>
<property name=viewClass
value=org.springframework.web.servlet.view.JstlView /> <form:form method=post modelAttribute=docenteModel>
<property name=prefix value=/WEB-INF/views/ />
<property name=suffix value=.jsp /> <table>
</bean> <tr>
<td>Nome:</td>
<bean id=propertyConfigurer <td><form:input path=nome /></td>
class=org.springframework.beans.factory.config.PropertyPlaceholderConfigurer </tr>
p:location=/WEB-INF/jdbc.properties /> <tr>
<td>Matrcula:</td>
<bean id=dataSource <td><form:input path=matricula /></td>
</tr>
class=org.apache.commons.dbcp.BasicDataSource destroy-method=close
<tr>
p:driverClassName=${jdbc.driverClassName}
<td>Titulao:</td>
p:url=${jdbc.databaseurl} p:username=${jdbc.username}
<td><form:input path=titulacao /></td>
p:password=${jdbc.password} /> </tr>
<tr>
<bean id=sessionFactory <td>
class=org.springframework.orm.hibernate4.LocalSessionFactoryBean> <input type=submit name=_eventId_inserir value=Salvar/>
<property name=dataSource ref=dataSource /> </td>
<property name=configLocation> <td>
<value>classpath:hibernate.cfg.xml</value> <input type=submit name=_eventId_cancelar value=Cancelar/>
</property> </td>
</tr>
<property name=hibernateProperties> </table>
</form:form>
<props>
<prop key=hibernate.dialect>${jdbc.dialect}</prop>
</body>
<prop key=hibernate.show_sql>true</prop>
</html>
</props>
</property>
</bean>

<tx:annotation-driven />
<bean id=transactionManager
class=org.springframework.orm.hibernate4.HibernateTransactionManager>
<property name=sessionFactory ref=sessionFactory />
</bean>

<webflow:flow-executor id=flowExecutor/>

<webflow:flow-registry id=flowRegistry>
<webflow:flow-location path=/WEB-INF/flows/inserirDocente.xml
id=inserirDocente />
</webflow:flow-registry>
Figura 7. Formulrio de cadastro de docentes

<bean class=org.springframework.webflow.mvc.servlet.FlowHandlerMapping>
<property name=flowRegistry ref=flowRegistry/>
Para construir esse formulrio fizemos uso dos pacotes de taglibs
<property name=order value=0/>
</bean> do Spring; em especial, do pacote form, como mostrado nos
trechos de cdigo iniciados por <form:input>. Essa taglib utili-
<bean class=org.springframework.webflow.mvc.servlet.FlowHandlerAdapter> zada para criar os campos do formulrio conforme verificado em
<property name=flowExecutor ref=flowExecutor/>
<form:input path=nome />. J a associao entre os formulrios
</bean>
e as respectivas classes na camada de modelo feita por meio da
<bean name=docenteController class=br.com.devmedia.gestaoacademicaweb propriedade modelAttribute na tag <form>, como vemos em
.control.DocenteController /> <form:form method=post modelAttribute=docenteModel>.
</beans>
Nesse trecho constatamos que o formulrio de cadastro de do-

28 Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia


cente associado classe da camada de modelo identificada por Listagem 12. Cdigo-fonte da pgina de cancelamento.
docenteModel.
<%@ page language=java contentType=text/html; charset=UTF-8
Essa identificao configurada no arquivo do fluxo, e a vere- pageEncoding=UTF-8%>
mos mais adiante, quando apresentarmos o contedo do arquivo <!DOCTYPE html PUBLIC -//W3C//DTD HTML 4.01 Transitional//EN
inserirDocente.xml. Nesse caso, a propriedade path usada nas http://www.w3.org/TR/html4/loose.dtd>
<html>
declaraes dos campos para indicar a que atributo da classe cada <head>
campo de formulrio ser associado. <meta http-equiv=Content-Type content=text/html; charset=UTF-8>
A passagem de uma pgina para outra que o SWF identifica <title>Insert title here</title>
</head>
como transio entre estados feita por meio do disparo de even- <body>
tos pelo usurio, ou seja, quando este clica em um boto, ou num <h3>Processo de cadastramento cancelado</h3>
</body>
link, por exemplo. Com isso, cada evento disponvel nas pginas
</html>
deve ser identificado (na sua propriedade name) pelo prefixo _even-
tId na declarao do elemento de pgina que foi construdo para Listagem 13. Cdigo-fonte da listagem de docentes.

dispar-lo. Por exemplo, o boto Salvar no formulrio de cadastro <%@taglib uri=http://java.sun.com/jsp/jstl/core prefix=c%>
de docentes identificado por _eventId_inserir, como pode ser vis-
to no trecho <input type=submit name=_eventId_inserir <html>
<head>
value=Salvar/>. <title>Listagem de Docentes</title>
Agora vamos criar os arquivos cancelado.jsp e listar_docentes. </head>
jsp, que representam, respectivamente, a pgina de resposta de <body>

cancelamento e a listagem dos docentes cadastrados. O cdigo <h3>Docentes Cadastrados</h3>


da pgina de resposta de cancelamento bastante simples e
<h3><a href=${flowExecutionUrl}&_eventId=novo>+ Novo Docente</a></h3>
apresentado na Listagem 12. J o cdigo-fonte da listagem de
<c:if test=${!empty docenteList}>
docentes demonstrado Listagem 13, enquanto sua aparncia <table border=1>
pode ser vista na Figura 8. <tr>
<th>Nome</th>
<th>Matrcula</th>
<th>Titulao</th>
<th>&nbsp;</th>
</tr>
<c:forEach items=${docenteList} var=docente>
<tr>
<td>${docente.nome} </td>
<td>${docente.matricula}</td>
<td>${docente.titulacao}</td>
<td><a href=${flowExecutionUrl}&_eventId=
excluir&docenteId=${docente.id}>Excluir</a></td>
</tr>
</c:forEach>
</table>
</c:if>

</body>
</html>

Figura 8. Listagem de Docentes


Agora que as pginas foram criadas podemos fazer a implemen-
No cdigo dessa pgina os eventos disponveis so cliques tao do fluxo da aplicao modificando o arquivo inserirDocente.
nos links para novo docente e excluir. Aqui importante xml, como demonstrado na Listagem 14. O primeiro elemento
lembrar que os eventos devem ser identificados pelo prefixo que devemos notar nesse arquivo a declarao da varivel
_eventId, e isso implementado na declarao dos links, como em docenteModel, feita no trecho <var name=docenteModel
<a href=${flowExecutionUrl}&_eventId=excluir&docenteId class=br.com.devmedia.gestaoacademicaweb.model.Do-
= ${docente.id}>. cente/>. Essa varivel utilizada para descrever a associao
Note tambm que inclumos no link o fluxo a que esse evento entre a classe Docente na camada de modelo e o formulrio de
se refere (no nosso caso, inserirDocente), por meio do parmetro cadastro de docentes.
flowExecutionUrl. O restante da pgina utiliza taglibs JSTL para Como demonstrado nessa listagem, os estados do fluxo so
percorrer uma coleo e exibir os registros de docente cadastrados descritos em ns XML com o sufixo -state. Visto que nosso pro-
no banco devidamente recuperados pelas demais camadas da jeto possui dois view-states (listagem de docentes e formulrio
aplicao. de cadastro de docentes) e um end-state (operao cancelada),

Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia 29


Aprenda a utilizar o Spring Web Flow

utilizamos os ns <view-state> e <end-state> para declarar Para isso, especificamos o n <evaluate>, como mostra o trecho <eva-
esses estados. luate expression=docenteController.adicionarDocente(docente-
Por sua vez, especificamos o handler do formulrio de cadastro Model)/>. Esse recurso utilizado novamente na listagem de docen-
de docentes com o n <action-state>, no trecho <action-state tes, conforme a marcao <evaluate expression=docenteController
id=inserirDocenteAction>, e definimos as transies em ns .listarDocentes() result=viewScope.docenteList/>, que faz com
<transition>. A propriedade on de uma transio indica em que que o mtodo listarDocentes() seja executado na renderizao da
evento ela deve ser disparada; enquanto a propriedade to, para listagem de docentes.
qual estado o usurio direcionado. Por exemplo, na marcao Nesse segundo exemplo vemos outro recurso do SWF ser
<transition on=cancelar to=cancelado />, uma vez dispa- utilizado: o retorno do mtodo armazenado em uma vari-
rado o evento cancelar o usurio ser encaminhado para o estado vel que pode ser acessada na camada de viso. A propriedade
cancelado. result da tag <evaluate> define o armazenamento do retorno
do mtodo listarDocentes() em uma varivel chamada do-
centeList. Nesse trecho, note que tambm indicado o escopo
Listagem 14. Cdigo-fonte do fluxo inserirDocente.xml.
da varivel (viewScope, que significa que a varivel estar
<?xml version=1.0 encoding=UTF-8?> disponvel apenas no estado em que ela foi declarada; no caso,
a view-state listar). Outros escopos existem, mas no os explo-
<flow xmlns=http://www.springframework.org/schema/webflow
xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance ramos nesse artigo.
xsi:schemaLocation=http://www.springframework.org/schema/webflow Com isso, a ltima coisa que falta para nosso projeto ser concludo
http://www.springframework.org/schema/webflow/
spring-webflow-2.0.xsd>
criar o banco de dados. Para tanto, vamos usar o script de criao
da tabela descrito na Listagem 15. Com isso nosso exemplo est
<var name=docenteModel class=br.com.devmedia.gestaoacademicaweb.model. pronto para ser testado, o que pode ser feito aps iniciar o Tomcat e
Docente/>
digitar, no navegador, a URL http://localhost:8080/inserirDocente.
<view-state id=form view=/WEB-INF/views/inserir_docente_form.jsp
model=docenteModel>
Listagem 15. Script de criao da tabela DOCENTES.
<transition on=inserir to=inserirDocenteAction />
<transition on=cancelar to=cancelado />
CREATE TABLE DOCENTES (
</view-state>
ID INT PRIMARY KEY AUTO_INCREMENT,
NOME VARCHAR(100),
<action-state id=inserirDocenteAction>
MATRICULA VARCHAR(100),
<evaluate expression=docenteController.adicionarDocente(docenteModel) />
TITULACAO VARCHAR(100)
<transition to=listar />
);
</action-state>

<view-state id=listar view=/WEB-INF/views/listar_docentes.jsp>


<on-render> Ivar Jacobson, GradyBooch e JamesRumbaugh, que podemos
<evaluate expression=docenteController.listarDocentes()
result=viewScope.docenteList/>
chamar de pais da Unified Modeling Language (UML), afirmam
</on-render> que um estado o momento durante o ciclo de vida de um
<transition on=novo to=form /> objeto no qual ele satisfaz algumas condies, executa algumas
<transition on=excluir to=listar>
<set name=requestScope.docenteId value=requestParameters.docenteId
atividades ou espera por eventos. Nesse artigo, vemos como esse
type=long /> conceito adotado para descrever a navegao do usurio, mais
<evaluate expression=docenteController.removerDocente(docenteId) /> especificamente, as pginas que ele pode visitar e os eventos que
</transition>
</view-state> dispara pelo caminho.
Esse conceito tornou possvel o encapsulamento do fluxo, dimi-
<end-state id=cancelado view=/WEB-INF/views/cancelado.jsp/> nuindo a escrita de cdigo, deixando a estrutura de navegao
</flow> do website mais clara e, eventualmente, permitindo que os fluxos
sejam reutilizados no s em outras partes do prprio site, mas em
outras aplicaes. Vale destacar que o cdigo, especialmente das
Para o evento de submisso do formulrio, declaramos uma tran- camadas de controle e viso, est mais simples do que o constru-
sio como <transition on=inserir to=inserirDocenteAction do usando outros frameworks MVC, como o Struts, ou o prprio
/>. Nesse trecho fazemos com que o action-state inserirDocenteAction Spring, na medida em que menos cdigo precisou ser escrito.
seja acionado quando o evento inserir for disparado (podemos ver Tambm importante ressaltar que o SWF perfeitamente in-
na Listagem 11 que esse evento est associado ao clique no boto tegrvel a outros frameworks MVC. No entanto, sua integrao
Salvar). J a operao adicionarDocente(), da classe DocenteCon- com o Spring MVC mais interessante, at pela obviedade de
troller, ser realizada durante o action-state inserirDocenteAction, fazer parte do mesmo projeto, assim como pelo mecanismo de
o que viabilizar a insero dos dados do formulrio de cadastro injeo de dependncia do Spring, algo bastante celebrado na
de docentes no banco. comunidade de desenvolvedores.

30 Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia


No que diz respeito estrutura do projeto, o fato dos fluxos Sendo assim, os recursos do SWF devem ser explorados de
serem organizados em um arquivo XML e identificados de forma forma bastante ampla para obter um melhor gerenciamento do
nica constitui mais uma vantagem do SWF, especialmente por workflow na plataforma web, o que nos possibilita afirmar que
deixar a estrutura da aplicao visvel e viabilizar o reuso. Outra o SWF ideal para construir aplicaes web em que as regras de
vantagem a possibilidade de organizar os fluxos em subfluxos negcio demandam guiar o usurio por fluxos bem controlados,
de maneira transparente, separando toda a lgica de negcio da estruturados e, ocasionalmente, reusveis.
lgica de navegao, uma inovao no que diz respeito ao padro
Model-View-Controller. Links:

Autor Site oficial do projeto Spring Web Flow.


http://projects.spring.io/spring-webflow/
Alessandro Jatob
jatoba@jatoba.org Site oficial do projeto Spring.
Mestre em Cincia da Computao pela UFRJ, Doutorando em https://spring.io/
Engenharia tambm pela UFRJ com Doutorado-Sanduche na Site oficial do Hibernate.
Universidade de Waterloo, no Canad. Trabalha com Java h quase 20 http://www.hibernate.org
anos, a maior parte deles liderando equipes de desenvolvedores em
projetos Web. Tambm professor universitrio, lecionando temas ligados ao desen- Site oficial do Apache Maven.
volvimento orientado a objetos. https://maven.apache.org/

Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia 31


Aprenda a utilizar o Spring Web Flow

32 Copyright - Proibido copiar ou distribuir. Todos os direitos reservados para DevMedia

Anda mungkin juga menyukai