You are on page 1of 32

Sumrio

06 Java 3D: Criando e movimentando formas geomtricas em Java


[ Miguel Diogenes Matrakas ]

Contedo sobre Boas Prticas

12 Qualidade no cdigo Java com os princpios S.O.L.I.D


[ Marcio de S. Justo de Oliveira ]

Contedo sobre Boas Prticas

20 Programao Orientada a Objetos (POO): reusabilidade e eficincia em seu cdigo Parte 2


[ John Soldera ]

Artigo no estilo Soluo Completa

25 Desenvolva aplicaes com Play! Framework


[ Luis Gustavo Souza ]
Assine agora e tenha acesso a
todo o contedo da DevMedia:
www.devmedia.com.br/mvp

Edio 45 2014 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 Davi Costa (davigc_08@hotmail.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.
Java 3D: Criando e movimentando formas geomtricas em Java

Java 3D: Criando e


movimentando formas
geomtricas em Java
Aprenda a movimentar formas geomtricas
utilizando a Java3D
Fique por dentro
A
biblioteca Java3D possibilita escrever aplicaes
com grficos tridimensionais, fornecendo as Este artigo apresenta uma introduo aos conceitos necessrios
ferramentas para criar, manipular e visualizar para movimentar formas geomtricas utilizando as ferramentas da
geometrias 3D. Nesta biblioteca, a organizao dos dados API Java3D, explicando a estrutura que deve ser criada para montar a
que representam os elementos que compem a imagem cena e os objetos de transformao necessrios para obter a movimen-
baseada em grafos. Isto quer dizer que os elementos da tao dos grficos tridimensionais. Junto com as explicaes, alguns
cena tridimensional so organizados em uma estrutura exemplos demonstrando os conceitos abordados sero analisados
hierrquica de dados, que recebe o nome de grafo de para facilitar a sua compreenso.
cena. A viso geral de como criar e manipular as geo-
metrias em um grafo de cena apresentada no artigo
Primeiros passos com a Java3D, publicado na easy Java ou a posio da forma no espao virtual criado pela aplicao. No
Magazine 36. Como apresentado neste primeiro artigo, restante do artigo os desenhos tridimensionais sero chamados
as informaes que representam um objeto tridimen- de formas, geometrias ou ainda modelos, j o termo objeto ser
sional so chamadas de modelo geomtrico, geometria utilizado apenas para denotar instncias de classes Java, definidas
ou simplesmente modelo. pelas APIs abordadas ou nos exemplos.
O grafo de cena utilizado para organizar os elementos
que formam o que se chama de universo. O universo Posicionando as formas
para uma aplicao grfica, ou mais especificamente Para posicionar uma forma geomtrica no espao necessrio
para uma cena tridimensional, deve conter todas as in- indicar o ponto que esta ocupa em relao origem do sistema
formaes necessrias para a gerao da(s) imagem(ens) de coordenadas, ou seja, define-se qual a distncia da forma ao
desejada(s). Em um grafo de cena esto presentes, alm ponto (0, 0, 0). Para realizar isso na Java3D, o objeto que repre-
dos dados que representam as geometrias dos elementos senta a forma que se deseja posicionar precisa estar associado
que devem aparecer na imagem, elementos que repre- a um objeto de transformao que implementa uma translao.
sentam aes, ou movimentos, que alteram a forma ou Isto realizado pela classe TransformGoup, na qual deve ser
a posio das geometrias definidas. Estas alteraes especificada a transformao a ser realizada e as geometrias nas
podem representar um simples deslocamento utilizado quais esta ser aplicada. A translao especificada chamando o
para posicionar corretamente o modelo, ou tambm ro- mtodo setTranslation() da classe Transform3D, que recebe como
taes e transformaes que alterem a forma do modelo parmetro um objeto do tipo Vector3f que representa o vetor de
geomtrico no qual est sendo aplicada. translao a que a forma ser submetida, ou seja, o quanto ser
Neste artigo sero discutidas as transformaes de deslocada em cada um dos eixos ordenados (x, y, z).
deslocamento e rotao juntamente com esquemas que No exemplo apresentado na Listagem 1, uma srie de formas
permitem criar movimentos, alm de demonstrar como so posicionadas em cada um dos eixos, sendo colocadas esferas
permitir ao usurio controlar algumas destas transfor- no eixo x, cones no eixo y e cilindros no eixo z. As formas criadas
maes, fazendo com que ele controle o ponto de viso tm tamanho de cinco centmetros, o que pode ser observado nas

6 easy Java Magazine Edio 45


chamadas de seus respectivos construtores, que so os primeiros Um objeto do tipo ViewingPlatform define o ponto de observao,
comandos em cada um dos trs laos presentes no cdigo. Cada ou seja, de onde se est olhando para os modelos que compem a
uma destas formas posicionada a cada 10 centmetros nos eixos cena, o tamanho da janela de visualizao e tambm caractersti-
ordenados, o que est especificado nos construtores dos objetos cas de como a imagem gerada a partir do grafo de cena.
do tipo Vector3f, utilizados para especificar a translao a ser A classe OrbitBehavior, por sua vez, movimenta um elemento
realizada em cada uma das geometrias declaradas. O resultado quando o mouse arrastado com um boto pressionado, incluindo
deste exemplo mostrado na Figura 1, porm a visualizao da
disposio dos cilindros prejudicada porque o eixo z representa
a profundidade em relao ao plano de viso do dispositivo de
sada, no caso o monitor.
Uma maneira de melhorar a visualizao dos cilindros alterar
a disposio dos eixos utilizados no modelo. Isto pode ser rea-
lizado permitindo ao usurio movimentar o ponto de viso em
volta da origem do sistema. Na Listagem 2 so acrescentadas as
chamadas para acrescentar este comportamento. Para permitir
que o usurio manipule o ponto de viso necessrio alterar as
caractersticas do objeto ViewingPlatform, que est vinculado
ao universo. A referncia a este objeto fornecida chamando o
mtodo getViewingPlatform() da classe SimpleUniverse.
O ViewingPlatform deve ser associado a um objeto de compor-
tamento para permitir ao usurio manipular o ponto de viso.
Um objeto de comportamento faz a associao entre um grafo
de cena, ou uma parte deste, e uma ao que deve ser executa-
da (comportamento) pelos modelos que fazem parte do grafo. Figura 1. Resultado da execuo do cdigo da Listagem 1

Listagem 1. Criao de um conjunto de geometrias ao longo dos eixos ordenados.

public class Eixos3 }


{
public Eixos3() // Eixo Z formado por cilindros
{ // Coordenadas do eixo Z variando de -1 metro at 1 metro em intervalos de 10 cm
// Cria o universo virtual for (float z = -1.0f; z <= 1.0f; z = z + 0.1f )
SimpleUniverse universo = new SimpleUniverse(); {
// Cria a raiz do grafo de cena Cylinder cilindro = new Cylinder(0.05f, 0.1f );
BranchGroup grupo = new BranchGroup(); TransformGroup tg = new TransformGroup();
Transform3D transform = new Transform3D();
// Eixo X formado por esferas transform.setTranslation(new Vector3f(.0f, .0f, z););
// Coordenadas do eixo X variando de -1 metro at 1 metro em intervalos de 10 cm tg.setTransform(transform);
for (float x = -1.0f; x <= 1.0f; x = x + 0.1f ) tg.addChild(cilindro);
{ grupo.addChild(tg);
Sphere esfera = new Sphere(0.05f ); }
TransformGroup tg = new TransformGroup();
Transform3D transform = new Transform3D(); // Cria uma luz direcional verde que brilha por 100m, a partir da origem
transform.setTranslation(new Vector3f(x, .0f, .0f )); Color3f luz1Cor = new Color3f(.1f, 1.4f, .1f ); // luz verde
tg.setTransform(transform); BoundingSphere limite = new BoundingSphere(new Point3d(0.0, 0.0, 0.0), 100.0);
tg.addChild(esfera); Vector3f luz1Direcao = new Vector3f(4.0f, -7.0f, -12.0f );
DirectionalLight luz1 = new DirectionalLight(luz1Cor, luz1Direcao);
// Adiciona a esfera transladada ao grafo de cena
luz1.setInfluencingBounds(limite);
grupo.addChild(tg);
grupo.addChild(luz1);
}

// Olha na direo dos eixos
// Eixo Y formado por cones
universo.getViewingPlatform().setNominalViewingTransform();
// Coordenadas do eixo Y variando de -1 metro at 1 metro em intervalos de 10 cm
for (float y = -1.0f; y <= 1.0f; y = y + 0.1f )
// Adiciona o grupo ao grafo de cena
{
universo.addBranchGraph(grupo);
Cone cone = new Cone(0.05f, 0.1f );
}
TransformGroup tg = new TransformGroup();
Transform3D transform = new Transform3D(); public static void main(String[] args)
transform.setTranslation(new Vector3f(.0f, y, .0f );); {
tg.setTransform(transform); new Eixos3();
tg.addChild(cone); }
grupo.addChild(tg); }

Edio 45 easy Java Magazine 7


Java 3D: Criando e movimentando formas geomtricas em Java

as aes de rotao, zoom e translao. Assim possvel permitir senhado em uma posio ligeiramente diferente. Isto realizado
que o usurio gire, desloque, aproxime ou afaste o elemento que alterando-se a posio do cubo aplicando-se sobre o mesmo uma
est controlando. O construtor desta classe recebe como pri- transformao de rotao. Portanto, para cada frame uma nova
meiro parmetro o Canvas no qual o comportamento deve ser rotao do cubo deve ser calculada e aplicada.
adicionado (a classe Canvas representa a rea de desenho que a
Java3D est utilizando para mostrar os modelos geomtricos), e
como segundo parmetro um conjunto de flags, ou sinais, para
configurar os comportamentos desejados, podendo-se ativar ou
desativar a rotao, a translao e o zoom. Por padro, todas estas
aes esto ativas.
No exemplo da Listagem 2, o mtodo getCanvas() da classe Sim-
pleUniverse utilizado para obter a referncia ao Canvas e o flag
REVERSE_ALL utilizado para inverter todos os movimentos
associados ao mouse, para que a movimentao seja mais intuitiva,
pois com o comportamento padro, ao se mover o mouse para
baixo, por exemplo, uma rotao para cima executada. Ao aplicar
este flag, a rotao segue a direo do movimento do mouse.
Uma observao importante que um objeto do tipo Orbit-
Behavior precisa ser informado sobre a regio na qual os com-
portamentos definidos por ele so vlidos. Com este intuito, um
objeto do tipo BoundingSphere, com centro em (0, 0, 0) e raio
100 instanciado e fornecido como parmetro ao mtodo set- Figura 2. Rotao dos eixos usando OrbitBehavior na Listagem 2
SchedulingBonds().
Estes passos configuram o objeto orbit, que agora precisa ser O primeiro passo para permitir que um modelo possua um
associado ao viewingPlatform chamando-se o mtodo setView- comportamento no grafo de cena criar um ramo do tipo Trans-
PlatformBehavior(). Com isto feito, o usurio pode modificar formGroup e informar que o mesmo ser modificado em tempo
o ponto de viso do universo ao pressionar o boto esquerdo de execuo, com o flag ALLOW_TRANSFORM_WRITE. Se isto
do mouse e arrastar. Isto faz com que a cmera possa rodar ao no for informado, a Java3D assume que o grupo esttico e as
redor do ponto (0, 0, 0), aproximar ou afastar a cmera ou ainda transformaes aplicadas neste ramo j esto prontas, ou seja, no
transladar em qualquer direo. Na Figura 2 pode ser visto um permitido alterar os seus valores em tempo de execuo, o que
resultado da rotao aplicada aos eixos cartesianos. no possibilita uma sequncia de transformaes nos modelos,
impossibilitando a visualizao de movimentos.
Listagem 2. Permitir ao usurio mudar o ponto de viso. No ramo do grafo de cena do tipo TransformGroup podem
ser adicionados modelos e comportamentos, sendo os compor-
// Olha na direo dos eixos
universo.getViewingPlatform().setNominalViewingTransform(); tamentos aplicados a todas as geometrias pertencentes ao ramo
ViewingPlatform viewingPlatform = universo.getViewingPlatform(); do grafo de cena. Para rotacionar um cubo, precisa-se ento criar
OrbitBehavior orbit = new OrbitBehavior(universo.getCanvas(), OrbitBehavior.
e adicionar um cubo e uma transformao de rotao ao grupo.
REVERSE_ALL);
BoundingSphere bounds = new BoundingSphere(new Point3d(0.0, 0.0, 0.0), Para exibir um cubo na cena, basta instanciar um objeto do tipo
100.0); ColorCube com o tamanho desejado e inclui-lo no grafo.
orbit.setSchedulingBounds(bounds);
O controle do movimento de rotao realizado por um ob-
viewingPlatform.setViewPlatformBehavior(orbit);
jeto da classe RotationInterpolator, que uma especializao
// Adiciona o grupo ao grafo de cena de Behavior. Para configurar a rotao necessrio fornecer
universo.addBranchGraph(grupo);
ao construtor de RotationInterpolator as informaes sobre o
nmero de vezes que a rotao ser aplicada e qual o tempo de
Movimento a partir da rotao cada rotao, sobre qual grupo a rotao ser aplicada, uma ma-
Os objetos que definem comportamentos na Java3D tambm triz de transformao e os ngulos mnimo e mximo da rotao
podem ser utilizados para especificar movimentos para os mode- em radianos.
los ou partes do grafo de cena. No prximo exemplo, apresentado A classe Alpha fornece os mtodos para converter um valor de
na Listagem 3, esta caracterstica demonstrada associando-se tempo em um valor no intervalo [0, 1], o que possibilita controlar
um comportamento de rotao a um cubo para fazer com que o a velocidade de rotao do cubo informando em quanto tempo,
mesmo gire em um de seus eixos. em milissegundos, deve ser completada uma volta. O primeiro
Para que o movimento de rotao seja percebido, uma sequncia parmetro do construtor da classe Alpha indica quantas vezes
de imagens deve ser gerada, sendo em cada uma delas o cubo de- o lao ser repetido, ou neste caso, quantas rotaes o cubo deve

8 easy Java Magazine Edio 45


realizar. O valor -1 indica que no h um limite estabelecido e o do cubo de diferentes ngulos, o controle sobre o ponto de visua-
lao ser repetido indefinidamente. O segundo parmetro, por lizao adicionado como no ltimo exemplo, permitindo que a
sua vez, informa o tempo, em milissegundos, que cada iterao cmera seja movimentada em volta do cubo. Na Figura 3 tem-se
deve demorar. um momento da rotao do cubo com o ngulo de visualizao
alterado para permitir a viso da sua face superior.
Listagem 3. Associando a uma geometria um movimento de rotao.

public class RotacionarCubo{

public RotacionarCubo(){
SimpleUniverse universo = new SimpleUniverse();
BranchGroup grupo = new BranchGroup();

// Cria o n Transformgroup e inicializa-o com a matriz identidade.
TransformGroup transform = new TransformGroup();
// Habilita a capacidade de escrita TRANSFORM_WRITE, para que o objeto
// de comportamento possa modific-lo em tempo de execuo.
transform.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
// Adiciona o TransformGroup raiz do grafo.
grupo.addChild(transform);

// Cria um cubo de 40cm de lado e adiciona-o ao grafo de cena.


transform.addChild(new ColorCube(0.4));

// Cria a matriz de transformao 3D
Transform3D matTransf = new Transform3D();
// Parmetros da transformao:
// Lao infinito, com durao de quatro segundos por rotao
Alpha alphaRot = new Alpha(-1, 4000);
Figura 3. Resultado do cdigo da Listagem 3
// Cria interpolador de rotao
RotationInterpolator rotacionar = new RotationInterpolator(alphaRot, trans- Movimentando e alterando a geometria
form,
matTransf, 0.0f, (float) Math.PI * 2.0f );
As transformaes aplicadas em um grupo podem ser calcula-
BoundingSphere limites = new BoundingSphere(new Point3d(0.0, 0.0, 0.0), das como no exemplo anterior ou podem ser uma resposta a um
100.0); estmulo externo, como um comando do usurio, ou ainda uma
rotacionar.setSchedulingBounds(limites);
grupo.addChild(rotacionar); combinao de ambas as situaes. Assim, parte do movimento
de um modelo pode ser controlado pelo usurio, como no caso da
universo.getViewingPlatform().setNominalViewingTransform(); direo de um personagem em um jogo, combinado com o clculo,
ViewingPlatform viewingPlatform = universo.getViewingPlatform();
OrbitBehavior orbit = new OrbitBehavior(universo.getCanvas(), OrbitBehavior. digamos, de sua velocidade. Para exemplificar esta situao, o pr-
REVERSE_ALL); ximo exemplo apresenta uma bola que se movimenta na vertical, do
BoundingSphere bounds = new BoundingSphere(new Point3d(0.0, 0.0, 0.0),
topo at a base da janela, e o usurio controla a posio horizontal
100.0);
orbit.setSchedulingBounds(bounds); da mesma com as teclas a e s (veja o cdigo na Listagem 4).
viewingPlatform.setViewPlatformBehavior(orbit); A criao do grafo de cena para este exemplo similar do
universo.addBranchGraph(grupo);
exemplo anterior, trocando-se o cubo por uma esfera e com a
}
adio de uma fonte de iluminao direcional. O ramo do grafo
public static void main(String[] args){ correspondente transformao criado da mesma maneira que
new RotacionarCubo();
}
no exemplo de rotao do cubo.
} O controle de posicionamento da bola realizado pela alterao
dos valores das variveis de instncia altura, posX e sentido. Estas
variveis so alteradas nos eventos gerados a partir do teclado para
Os intervalos de rotao sero calculados pela classe RotationIn- o posicionamento horizontal e nos eventos gerados a partir de um
terpolator de acordo com o nmero de frames que sero exibidos objeto do tipo Timer para o posicionamento vertical.
durante o tempo de rotao. Os parmetros para a rotao so Como neste caso o cdigo de alterao, ou seja, as transforma-
especificados em uma matriz de transformao, representada pelo es aplicadas ao modelo, dependem de fatores externos (eventos
objeto do tipo Transform3D, que recebe os valores da transforma- de teclado e Timer) e no apenas dos parmetros definidos no
o aplicada em cada um dos frames a serem exibidos. cdigo, os objetos TransformGroup e Transform3D so de-
Por ltimo necessrio especificar os limites onde estas trans- clarados como atributos da classe, permitindo assim que seus
formaes so vlidas, ou seja, qual a regio do universo que valores sejam alterados pelos mtodos de tratamento de eventos,
ser afetada pelo comportamento definido e associado ao grupo modificando a transformao aplicada bola de acordo com os
de transformaes. Para que o usurio possa visualizar a rotao comandos do usurio.

Edio 45 easy Java Magazine 9


Java 3D: Criando e movimentando formas geomtricas em Java

A posio da bola na imagem controlada por dois elementos: nos quais a posio vertical deve ser alterada para cima ou para
um correspondente ao posicionamento horizontal, controlado baixo, alterando-se o valor da varivel altura. Este temporizador
pelo usurio, e outro correspondente ao posicionamento verti- iniciado ou parado no mtodo actionPerformed() juntamente
cal, controlado por um temporizador, para indicar os instantes com o evento do prprio temporizador, que ocorre a cada 30

Listagem 4. Exemplo que implementa uma bola quicando.

public class BolaSaltando extends JFrame implements ActionListener, KeyListener{ SimpleUniverse universo = new SimpleUniverse(canvas3d);
universo.getViewingPlatform().setNominalViewingTransform();
private Button ini = new Button(Iniciar); universo.addBranchGraph(cena);
private TransformGroup transformGroup; }
private Transform3D matrizTransf = new Transform3D();
private float altura = 0.0f; // chamado quando uma tecla pressionada.
private float sentido = 1.0f; // subindo ou descendo public void keyPressed(KeyEvent e) {
private Timer tempo; //Verifica se a tecla pressionada foi s
private float posX = 0.0f; if (e.getKeyChar() == s) {
if(posX < 1f )
public BranchGroup criarGrafoCena() posX = posX + .01f;
{ }
// Cria a raiz do grafo de cena // Verifica se a tecla pressionada foi a
BranchGroup grupo = new BranchGroup(); if (e.getKeyChar() == a) {
transformGroup = new TransformGroup(); if(posX > -1f )
transformGroup.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE); posX = posX - .01f;
grupo.addChild(transformGroup); }
}
// Cria uma esfera e a adiciona ao grafo de cena
Sphere esfera = new Sphere(0.25f ); // chamado quando uma tecla liberada.
transformGroup = new TransformGroup(); public void keyReleased(KeyEvent e){
transformGroup.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE); }
Transform3D pos1 = new Transform3D();
pos1.setTranslation(new Vector3f(0.0f, 0.0f, 0.0f )); // chamado quando uma tecla teclada
transformGroup.setTransform(pos1); public void keyTyped(KeyEvent e){
transformGroup.addChild(esfera); }
grupo.addChild(transformGroup);
public void actionPerformed(ActionEvent e){
// Cria a luz vermelha e a adiciona ao grafo // inicia o temporizador quando o boto clicado
BoundingSphere limite = new BoundingSphere(new Point3d(0.0, 0.0, 0.0), 100.0); if (e.getSource() == ini){
Color3f luz1Cor = new Color3f(1.0f, 0.0f, 0.2f ); if (!tempo.isRunning()) {
Vector3f luz1Direcao = new Vector3f(4.0f, -7.0f, -12.0f ); ini.setLabel(Parar);
DirectionalLight luz1 = new DirectionalLight(luz1Cor, luz1Direcao); tempo.start();
luz1.setInfluencingBounds(limite); } else {
grupo.addChild(luz1); ini.setLabel(Iniciar);
tempo.stop();
// Configura a luz ambiente e a adiciona ao grafo }
Color3f luzAmbienteCor = new Color3f(1.0f, 1.0f, 1.0f ); } else {
AmbientLight luzAmbiente = new AmbientLight(luzAmbienteCor); altura += .03 * sentido;
luzAmbiente.setInfluencingBounds(limite); if (Math.abs(altura * 2) >= 1)
grupo.addChild(luzAmbiente); sentido = -1.0f * sentido;
if (altura < -0.4f ) {
return grupo; matrizTransf.setScale(new Vector3d(1.0, .8, 1.0));
} } else {
matrizTransf.setScale(new Vector3d(1.0, 1.0, 1.0));
public BolaSaltando() { }
// Configura o ambiente do Applet matrizTransf.setTranslation(new Vector3f(posX, altura, 0.0f ));
setLayout(new BorderLayout()); transformGroup.setTransform(matrizTransf );
GraphicsConfiguration config = SimpleUniverse.getPreferredConfiguration(); }
Canvas3D canvas3d = new Canvas3D(config); }
add(Center, canvas3d);
canvas3d.addKeyListener(this); public static void main(String[] args){
tempo = new Timer(30, this); System.out.println(Programa Iniciado);
BolaSaltando bolaSaltando = new BolaSaltando();
Panel painel = new Panel(); bolaSaltando.addKeyListener(bolaSaltando);
painel.add(ini); bolaSaltando.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
add(North, painel); bolaSaltando.setSize(256, 256);
ini.addActionListener(this); bolaSaltando.setVisible(true);
ini.addKeyListener(this); }
}
// Cria uma cena e a adiciona ao universo virtual
BranchGroup cena = criarGrafoCena();

10 easy Java Magazine Edio 45


milissegundos, conforme a sua configurao (tempo = Timer(30,
this);). Quando ocorre o evento do temporizador, a posio ver-
tical da esfera atualizada e os limites de seu movimento so
verificados. Diferente do caso da rotao do cubo no exemplo
anterior, quando se utilizou um interpolador, o movimento da
bola sofre uma alterao em seu sentido dependendo de sua
posio. Por isto necessrio utilizar o temporizador e controlar
o movimento diretamente. Figura 4. Resultado da execuo do cdigo da Listagem 4
Na movimentao vertical da bola, caso o limite superior seja
atingido, o sentido do movimento invertido. J no caso do limite
inferior, antes de inverter o movimento, uma verificao adicio- A partir do contedo explorado forma-se uma base para o incio
nal realizada. Assim, caso o limite esteja se aproximando, uma do estudo sobre o desenvolvimento de aplicaes que fazem a
nova transformao adicionada bola, alterando a sua forma sntese de imagens (geram imagens) com base na definio de
de maneira a achatar a esfera e simular o choque da bola com o modelos geomtricos. Como voc poder constatar, os mtodos
solo. Este efeito conseguido com uma transformao de escala, de controle utilizados para posicionar os modelos podem ser
na qual apenas o componente vertical da bola alterado. Isto incrementados para que transformaes mais suaves sejam con-
conseguido a partir dos parmetros (1.0, 0.8 e 1.0) passados ao seguidas, ou uma combinao mais complexa de parmetros pode
construtor do objeto Vector3d, parmetros do mtodo setScale(). ser utilizada para controlar o movimento de modelos que podem
Estes parmetros indicam o quanto cada dimenso deve ser altera- ser parte de um jogo ou de uma simulao, por exemplo.
da. O valor 1 indica que no h alterao, um valor menor do que Estas tcnicas, em conjunto, podem ser adotadas em diferentes
1 indica uma reduo do tamanho do modelo e um valor maior ramos do grafo de cena, o que permite um controle ainda mais
do que um indica um aumento do tamanho do modelo. detalhado dos elementos, viabilizando, por exemplo, que dois
Por uma questo de simplicidade, a transformao de escala usurios controlem personagens diferentes em um jogo. Sendo
aplicada na esfera como um evento nico, porm este comporta- assim, continue explorando esta API. A sua criatividade ditar o
mento no o correto. O ideal seria a utilizao de outra varivel limite para ela quanto criao de cenrios e objetos 3D.
de controle para que a transformao de escala seja realizada
gradualmente, da mesma maneira que a transformao de trans-
lao (posicionamento).
Esta transformao de escala aplicada quando a posio da
Autor
bola se aproxima do limite inferior estabelecido para o movimento,
porm a transformao de translao, que controla o posiciona- Miguel Diogenes Matrakas
mento da bola depende dos eventos de teclado e do temporizador. mdmatrakas@yahoo.com.br
A matriz de transformao correspondente translao depende Mestre em Informtica pela PUC-PR e doutorando em
Mtodos Numricos em Engenharia, pela UFPR (Universidade
dos valores das variveis altura e posX. A altura da bola depende
Federal do Paran). Trabalha como professor de Java h quatro anos nas
do tempo transcorrido, j a sua posio horizontal depende do
Faculdades Anglo-Americano de Foz do Iguau.
controle do usurio. Sendo assim, a atualizao da varivel que
controla a posio horizontal da bola realizada no mtodo de
tratamento de eventos do teclado keyPressed(), no qual verifi-
cada qual tecla foi pressionada e a varivel posX incrementada Links:
ou decrementada de acordo, enquanto a mesma no atingir os
Site oficial para download da biblioteca Java 3D.
limites estabelecidos.
www.oracle.com/technetwork/java/javase/tech/index-jsp-138252.html
O resultado dos movimentos associados bola pode ser visu-
alizado na Figura 4, na qual a sequncia de imagens representa Instrues de instalao da Java3D.
a bola movendo-se para baixo na imagem da esquerda, depois a http://download.java.net/media/java3d/builds/release/1.5.1/README-download.html
bola aproximando-se da base, na imagem do centro, e por ltimo
Site do grupo de desenvolvimento da Java3D.
a bola aproximando-se do limite vertical superior, no qual no https://java3d.java.net/
aplicada a transformao de escala.

Edio 45 easy Java Magazine 11


Qualidade no cdigo com os princpios S.O.L.I.D.

Qualidade no cdigo com


os princpios S.O.L.I.D.
Como criar um design slido atravs dos cinco
princpios da Orientao a Objetos

Fique por dentro


muito comum, no nosso dia a dia de desenvolvi-
mento, nos depararmos com sistemas detentores
de um cdigo no reutilizvel, com classes for- Este artigo tem por objetivo fornecer algumas propostas para o
temente acopladas e no extensveis. Com isso, tanto o aperfeioamento do uso da Orientao a Objetos, atravs de uma
trabalho de alterar funcionalidades j existentes quanto breve apresentao do tema e da anlise dos princpios S.O.L.I.D.,
o de adicionar novas se torna uma tarefa muito comple- defendidos por Robert C. Martin. Princpios que, se seguidos, aumen-
xa, dispondo de demasiado tempo e esforo. taro de forma significativa a simplicidade e a qualidade do cdigo,
Um sistema, quando implementado dentro de um caractersticas que trazem como consequncia uma maior facilidade
cenrio como o exposto, se torna frgil e nos remete a para a manuteno do sistema.
uma srie de situaes de erro. Erros se apresentam em
qualquer mdulo do projeto quando outra rea do cdi-
go alterada. Problemas como classes com mais de uma agentes damos o nome de objetos e a cada um deles so atribudas
responsabilidade, mtodos no extensveis e interfaces responsabilidades, ou seja, eles ficam responsveis por executar
poludas consistem em falhas que podem ser de fato tarefas especficas. Atravs dessa interao entre os objetos tarefas
reduzidas com a prtica do desenvolvimento slido. computacionais so realizadas.
Uma implementao slida aquela em que as res- Mas como realizar essa interao de forma limpa, legvel e
ponsabilidades so bem definidas e distribudas, e os organizada conforme descrito anteriormente? Para desenvolver
comportamentos existentes podem ser reutilizados e um sistema possuidor de um cdigo com baixo acoplamento,
facilmente estendidos para outras funcionalidades. devidamente modularizado, com suas responsabilidades bem
Com o intuito de ajudar o desenvolvedor a alcanar essa definidas, Robert C. Martin, por volta dos anos 90, compilou cinco
meta, foi criado o acrnimo S.O.L.I.D. Este acrnimo princpios da orientao a objetos que visam nos ajudar com a
simplesmente a juno de cinco princpios que, quando tarefa de obter um cdigo mais slido (S.O.L.I.D.).
adotados, se tornam garantia de um cdigo mais robusto Martin, mais conhecido como Uncle Bob, um grande nome
e flexvel. na comunidade de desenvolvimento de software, trabalhando
Com base nisso, o objetivo deste artigo apresentar na rea desde 1970. Fundador e presidente da Object Mentor Inc.
de forma prtica e abrangente o uso destes princpios, e autor de livros como Clean Code A Handbook of Agile Software
visando levar ao desenvolvedor o conhecimento ne- Craftsmanship e Clean Coder A Code of Conduct for Professional
cessrio para comear a aplic-los em seu ambiente de Programmers. Martin, em sua publicao sobre SOLID, chama
programao, seja em projetos novos ou em legados. nossa ateno para quatro perguntas. O que de fato um design
orientado a objetos? Do que ele trata? Quais so seus benefcios?
O Paradigma da Orientao a Objetos E o quanto ir nos custar sua implementao? Essas perguntas
O verdadeiro Design de Software aquele em que podem parecer simplrias numa poca em que todos os desenvol-
toda a arquitetura pensada consiste na produo de vedores de software esto usando alguma linguagem orientada
cdigo reutilizvel, coeso, desenvolvido de forma leg- a objetos, seja ela de qualquer tipo. No entanto, so perguntas
vel e organizada. Isto o que pregam as boas prticas importantes, segundo ele, tendo em vista que a maioria de ns
da Orientao a Objetos: trazer benefcios reais para o usa essas linguagens sem saber o porqu e sem saber como tirar
desenvolvimento de softwares. o maior benefcio delas.
O paradigma da orientao a objetos nos apresenta J a criao do acrnimo S.O.L.I.D. propriamente dito, foi intro-
uma coleo de diversos agentes interconectados. A estes duzida por Michael Feathers, igualmente integrante da Object

12 easy Java Magazine Edio 45


Mentor Inc. e autor do livro Working Effec-
tively with Legacy Code. Feathers, na busca
por facilitar a absoro da ideia, percebeu
que a juno das cinco letras iniciais dos
princpios, a saber: Single Responsability
Principle, Open Closed Principle, Liskov
Substitution Principle, Interface Segregation
Principle e Dependency Inversion Principle,
formavam a palavra Solid, que nos remete
aos objetivos implcitos dos princpios, isto Figura 1. Excesso de responsabilidades para a classe Retangulo
, um desenvolvimento mais slido.
princpio afirma que no se deve forar diversos erros inesperados quando altera-
Os cinco princpios da OO os clientes a dependerem de interfaces dos. Para exemplificar melhor o problema
Muitos dos profissionais envolvidos com que no utilizaro de fato. Ou seja, nossos aqui apresentado, vamos considerar o
o desenvolvimento de software orientado mdulos devero possuir poucos compor- design da Figura 1, onde uma classe Re-
a objetos possuem o conhecimento acad- tamentos e apenas aqueles que realmente tangulo possui dois mtodos. Um mtodo
mico sobre acoplamento, coeso e encapsu- sero utilizados. Interfaces com muitos ir simplesmente desenhar um retngulo
lamento. Mas esses mesmos profissionais, comportamentos se distribuem ao longo na tela e o outro calcular a sua rea.
em sua maioria, no tm ideia de como do sistema e acabam por dificultar futuras Como pode ser observado, duas aplica-
alcanar esses objetivos, conseguindo um manutenes; es fazem uso da classe Retangulo, sendo
cdigo com alta coeso, baixo acoplamento Dependency Inversion Principle (DIP) uma delas a Aplicao Geomtrica, que
e forte encapsulamento. disso que trata Princpio da Inverso de Dependncias. Esse apenas far uso do mtodo calcularArea()
o S.O.L.I.D, que de forma simples pode ser princpio nos diz que devemos depen- e assim obter o resultado esperado, e a
entendido como um guia que traz diretri- der apenas de classes abstratas e no de outra a Aplicao Grfica, que no apenas
zes a serem seguidas para o alcance desses concretas. Classes abstratas quase nunca calcula a rea, mas tambm apresenta
objetivos. So elas: mudam. Assim, o cdigo fica desacoplado, a figura desenhada via interface com o
Single Responsability Principle (SRP) facilitando futuras mudanas no compor- usurio.
Princpio da Responsabilidade nica. Esse tamento delas. Este design claramente viola a SRP (Single
princpio nos diz que toda classe deve Responsability Principle), pois a classe Re-
possuir uma nica responsabilidade. As- Tais princpios, se colocados em prtica tangulo possui duas responsabilidades:
sim, podemos ter um cdigo mais coeso, de forma concreta, se tornam garantia de calcular a rea e desenhar a figura. Caso
simples e reutilizvel, de forma que con- um cdigo de evoluo fcil e de mudan- qualquer alterao na Aplicao Grfica
sigamos evitar diversas mudanas sendo as simples, que sero feitas em pontos resulte em mudanas na classe Retangulo,
propagadas ao longo do projeto; especficos do nosso sistema. Ento, como consequentemente isso forar uma nova
Open Closed Principle (OCP) Prin- aplicar esses princpios no nosso dia a dia e compilao, novos testes e um novo deploy
cipio do Aberto Fechado. Com base nesse tornar essas prticas reais dentro de nossos da Aplicao Geomtrica, pois existe um
princpio, o comportamento de nossas projetos? Este o tema que ser abordado acoplamento entre esses sistemas atravs
classes deve ser extensvel para outras com exemplos ao longo desse artigo. da mesma classe.
classes, sem que o mesmo sofra quaisquer Para resolver esse problema devemos
modificaes para isso. Os comporta- Princpio da Responsabilidade nica separar completamente as responsabilida-
mentos podero ser estendidos seja por Como o prprio nome j diz, nossas classes des em classes diferentes, como mostrado
herana, composio ou atravs do uso devem possuir uma nica funo, isto , elas na Figura 2. Este novo design separa a
de interfaces; tm de ser responsveis apenas pela execu- responsabilidade do clculo geomtrico
Liskov Substitution Principle (LSP) o do objetivo para o qual foram criadas. em uma nova classe, chamada Retangu-
Princpio da Substituio de Liskov. Esse Quando uma classe possui diversas respon- loGeometrico. Agora qualquer mudana
princpio nos alerta sobre o cuidado no sabilidades, cria-se um forte acoplamento in- feita no processo de como o retngulo
uso da Herana. Ele afirma que devemos terno, pois certamente suas funes estaro apresentado para o usurio no ir in-
ser capazes de usar uma classe derivada no dependentes umas das outras, ao passo que terferir no funcionamento da Aplicao
lugar de uma classe me, e essa derivao qualquer alterao em um desses mtodos Geomtrica.
deve possuir a capacidade de se comportar pode causar erros em outros, tornando sua
da mesma forma; manuteno trabalhosa. Princpio do Aberto Fechado
Interface Segregation Principle (ISP) Esse tipo de acoplamento nos leva a Mudanas sempre iro acontecer em
Princpio da Segregao de Interfaces. Esse um projeto frgil, que tende a apresentar nossos sistemas, pois eles precisam mudar

Edio 45 easy Java Magazine 13


Qualidade no cdigo com os princpios S.O.L.I.D.

e evoluir. Em virtude disso, surge o desa- que permitam suas extenses, mas fechadas desenhada. Com isso, para cada nova
fio de criar um projeto estvel mediante para modificaes. Na Figura 3 podemos forma que necessite ser desenhada haver
essas mudanas. Vejamos o que apresenta ver no exemplo de nossa aplicao grfica mais um if para represent-la.
o Open Closed Principle (OCP) em relao como ela viola o conceito do OCP. Respon- Na Figura 4 apresentamos um exemplo
a essa meta. svel por desenhar diferentes formas geo- de design que ir suportar o OCP. Nesse
O princpio do OCP prega a criao de mtricas, do jeito que o design se encontra, design temos o mtodo abstrato dese-
comportamentos em nossas classes que podemos perceber que seramos obrigados nhar() na classe Forma sinalizando que
possam ser estendidos para outras quando a alterar o cdigo da classe EditorGrafico toda classe do tipo forma ter a capacidade
houver necessidade de mudanas por parte cada vez que uma nova forma fosse adi- de desenhar. Assim, tanto a classe Circulo,
dos requisitos. Isto porque alterar compor- cionada lgica. quanto a classe Retangulo, bem como as
tamentos j em funcionamento demanda Na Listagem 1 vemos uma representao demais formas que venham a surgir, se
um grande esforo, j que todas as depen- em cdigo sobre o design exposto que fere tornam elas prprias as responsveis por
dncias do sistema que possuem interao de forma clara o princpio do OCP. Como executar a ao de desenhar, no sendo
com as funcionalidades a serem alteradas pode ser visto no mtodo desenharFor- mais necessria quaisquer alteraes na
precisariam ser novamente testadas. ma() da classe EditorGrafico, o mtodo classe EditorGrafico.
Sendo assim, nossas entidades, mdulos possui ifs encadeados que, atravs de um Como podemos verificar, a classe Editor-
e funes devem estar abertas, de modo tipo informado, definiro qual forma ser Grafico agora recebe apenas a forma que
ser desenhada e executa o seu mtodo
desenhar(). Observe a representao desse
design em cdigo na Listagem 2. Ao criar-
mos o mtodo abstrato desenhar() na clas-
se Forma, garantimos que todas as classes
que a estendam possuam essa capacidade.
Assim, o mtodo desenharForma() da
classe EditorGrafico fica apenas com a
responsabilidade de receber um objeto
do tipo Forma como parmetro e, atravs
Figura 2. Responsabilidades separadas corretamente, respeitando o SRP
dele, invocar seu mtodo desenhar().
A partir do momento em que a respon-
sabilidade de desenhar movida para as
classes concretas, o risco de afetar fun-
cionalidades antigas quando novas so
criadas reduzido consideravelmente.

Princpio da Substituio de Liskov


Esse princpio nos alerta para o cuidado
com o uso da herana. Certamente este
um recurso poderoso e justamente
por isso que devemos empreg-lo com
responsabilidade.
Figura 3. A classe EditorGrafico possui comportamentos no extensveis
A herana adotada quando se deseja
reutilizar um determinado cdigo de
outra classe, ou seja, reaproveitar o com-
portamento existente. No entanto, ao usar
herana, muito comum disponibilizar
para as classes filhas diversos mtodos e
atributos que as mesmas no iro utilizar e
que, portanto, no precisariam ter acesso.
O prprio James Gosling (pai da lingua-
gem Java) chama a nossa ateno para
o uso indevido da herana, afirmando:
Voc deve evitar implementar herana
Figura 4. Implementando o princpio da OCP sempre que possvel..

14 easy Java Magazine Edio 45


Listagem 1. OCP Mal exemplo de codificao. Isso nos mostra a fragilidade desse tipo de implementao, pois
se o cdigo da classe me sofrer quaisquer mudanas, suas classes
public class EditorGrafico {
filhas podero necessitar de mudanas tambm. Essa fragilidade
public void desenharForma(Forma forma) { pode ser encontrada dentro da implementao do prprio Java,
if(forma.tipo == 1) {
desenharCirculo(forma);
como o exemplo da classe Properties, que estende a classe
} Hashtable. Podemos passar para Hashtable qualquer objeto
else if(forma.tipo ==2){ como chave e valor, desde que o objeto no esteja nulo. J no caso
desenharRetangulo(forma);
} da classe Properties, esta deveria receber apenas objetos do tipo
} String para chave e valor.
Nesta classe, at temos mtodos como getProperty() e set-
public void desenharCirculo(Circulo circulo) {...}
Property(), responsveis por obter e fornecer valores do tipo
public void desenharRetangulo(Retangulo retngulo) {...} String. Contudo, mtodos como put() e putAll(), originrios de

} Hashtable, continuam disponveis em Properties, permitindo que
valores de qualquer tipo sejam passados para a mesma. Vejamos
public class Forma { um exemplo na Listagem 3.
int tipo;
}
Listagem 3. Exemplo de violao do LSP.
public class Circulo extends Forma {

Circulo() { Hashtable matricula = new Properties();


super.tipo = 1;
} matricula.put(Marcio, 3542);
} matricula.put(Marcelo, 4433);

public class Retangulo extends Forma { // um pequeno engano na prxima linha:


// 3224 ao invs de 3224
Retangulo() {
super.tipo = 2; matricula.put(Joaquim, 3224);
} ((Properties)matricula).list(System.out);
}
Este cdigo resultar em uma exceo:
Listagem 2. OCP O bom exemplo de codificao.
Marcio=3542
public class EditorGrafico { Exception in thread main java.lang.ClassCastException:
java.lang.Integer cannot be cast to java.lang.String
public void desenharForma(Forma forma) { at java.util.Properties.list(Unknown Source)
forma.desenhar(); at UseProperties.main(UseProperties.java:9)
}
}

public class Forma {


A motivao para o uso da Herana a reutilizao de cdigo.
abstract void desenhar(); No entanto, devido aos problemas apresentados, esta deve ser evi-
} tada sempre que possvel. Felizmente, existe uma alternativa mais
public void Retangulo extends Forma {
eficaz: a composio. Com ela conseguimos reaproveitamento de
public void desenhar() { cdigo sem quebrar o encapsulamento de nossas classes.
//desenhar o Retangulo No caso da classe Properties, para que ela reutilize os compor-
}
} tamentos existentes em Hashtable empregando a composio,
bastaria criar um atributo privado do tipo Hashtable e, com isso, o
public void Circulo extends Forma { mtodo setProperty() seria o responsvel por delegar a invocao
public void desenhar() {
//desenhar o Circulo a hashtable.put(). Dessa forma somente os mtodos necessrios
} seriam expostos.
}
Um relacionamento baseado em herana traz mais dificuldades
no momento de mudanas referentes interface de uma super-
Ao herdarmos explicitamente uma classe concreta, ficamos pre- classe. Isso porque mudanas no cdigo da classe me podem
sos a uma implementao especfica, a classe filha passa a conhe- vir a quebrar o cdigo implementado em qualquer uma de suas
cer de forma exagerada o cdigo interno da sua classe me. Este subclasses. Por exemplo, em uma determinada classe Trabalhador,
procedimento nos deixa acoplados demais superclasse. Dessa na qual seja necessria uma alterao no tipo de retorno de um
forma, podemos notar claramente uma quebra no encapsulamento dos mtodos pblicos, resultaria em uma quebra do cdigo que
a partir do momento em que uma subclasse fica dependente do invoca este mtodo em qualquer classe que seja uma referncia
comportamento da superclasse para realizar suas operaes. do tipo Trabalhador ou qualquer subclasse de Trabalhador que

Edio 45 easy Java Magazine 15


Qualidade no cdigo com os princpios S.O.L.I.D.

subscreva este mtodo. Como consequncia disso, as classes que Listagem 5. Exemplo da fragilidade no uso da Herana.
possuem ligao direta no iro compilar at que as alteraes
public class Horas {
para equiparar o tipo de retorno dos mtodos subscritos a partir
da superclasse sejam feitas em cada um deles. J a composio private int trabalhadas;
nos fornece uma abordagem com um cdigo mais fcil de mudar, public Horas(int trabalhadas) {
pois ao contrrio da herana, mudanas realizadas no cdigo da this.trabalhadas = trabalhadas;
classe final (antes classe me) no necessariamente resultariam }

em mudanas na classe de entrada (antes subclasse), tornando public int getTrabalhadas() {


assim o encapsulamento mais forte. return trabalhadas;
}
Nas Listagens 4, 5 e 6 podemos ver uma amostra do benefcio }
adquirido com o uso da composio. Na Listagem 4 apresenta-
public class Trabalhador {
mos o exemplo descrito anteriormente, que diz respeito classe
Trabalhador. Esta herdada pela classe Funcionario, que tem public Horas horasTrabalhadas() {
como cliente a classe ExemploUm; e esta ltima, por sua vez, ir system.out.println(Contabilizando horas trabalhadas);
return new Horas(8);
executar o programa para obter a quantidade de horas trabalhadas }
de determinado funcionrio. }

//Funcionario compila e continua funcionando


public class Funcionario extends Trabalhador {
Listagem 4. Exemplo de uma classe usando herana. }

public class Trabalhador { //Esta implementao no ir mais compilar


public class ExemploUm {
public int horasTrabalhadas() {
system.out.println(Contabilizando horas trabalhadas ); public static void main(String[] args) {
return 8;
} Funcionario funcionario = new Funcionario();
} int horas = funcionario.horasTrabalhadas();
}
public class Funcionario extends Trabalhador { }
}
Listagem 6. Exemplo do uso da composio para favorecer LSP.
public class ExemploUm {
public class Horas {
private int trabalhadas;
public static void main(String[] args) {
public Horas(int trabalhadas) {
this.trabalhadas = trabalhadas;
Funcionario funcionario = new Funcionario(); }
int horas = funcionario.horasTrabalhadas();
} public int getTrabalhadas() {
} return trabalhadas;
}
}

Ao executarmos o cdigo da classe ExemploUm iremos obter public class Trabalhador {


como resposta a quantidade de horas e a mensagem impressa
public Horas horasTrabalhadas() {
Contabilizando horas trabalhadas. Isso porque Funcionario reu- system.out.println(Contabilizando horas trabalhadas);
tiliza o mtodo horasTrabalhadas() ao herd-lo de Trabalhador. return new Horas(8);
}
Mas, e se em algum momento no futuro houver a necessidade }
de mudar o valor de retorno do tipo int do mtodo horasTraba-
lhadas() para o tipo Horas? Isso resultaria em uma quebra de public class Funcionario {

cdigo da classe cliente ExemploUm, mesmo que sua referncia private Trabalhador trabalhador = new Trabalhador();
direta seja apenas para com a classe Funcionario. Vejamos essa
public int horasTrabalhadas() {
demonstrao na Listagem 5. Horas horas = trabalhador.horasTrabalhadas();
J na Listagem 6 podemos ver como a composio prov uma return horas.getTrabalhadas();
}
alternativa para Funcionario no momento de obter a quantidade }
de horas trabalhadas. Ao invs de estender Trabalhador, Funcio-
public class ExemploUm {
nario pode possuir uma referncia para determinada instncia de
public static void main(String[] args) {
Trabalhador e definir seu prprio mtodo horasTrabalhadas(). Funcionario funcionario = new Funcionario();
Na abordagem da composio, a classe de entrada, antiga sub- int horas = funcionario.horasTrabalhadas();
}
classe, agora passa a ter sua prpria implementao de mtodo, }
que far uma chamada explcita dele mesmo, porm, correspon-

16 easy Java Magazine Edio 45


dente ao mtodo da classe final, antiga superclasse. Para essa Listagem 7. Exemplo de violao da ISP.
chamada explcita do mtodo damos o nome de delegao. Essa
abordagem prov um forte encapsulamento, pois alteraes na public interface ITrabalhador {
public void trabalhar();
classe final no necessariamente resultaro em quebra de cdigo public void comer();
na classe de entrada. }
public class Trabalhador implements ITrabalhador {
public void trabalhar() {
Princpio da Segregao de Interfaces // trabalhando...
No momento de projetar o design de alguma aplicao devemos }
ter bastante ateno com a criao dos mdulos. Estes devem sem-
public void comer() {
pre ser os mais abstratos possveis, pois medida que o sistema // comendo...
evolui novos mdulos se tornam necessrios. }
}
Diante da necessidade de estender a aplicao, haver o caso public class TrabalhadorExcepcional implements ITrabalhador {
de reaproveitar determinadas interfaces. No entanto, para isso, public void trabalhar() {
estas devero ser consideravelmente abstratas, pois nossas classes // trabalhando...
}
clientes no devem ser foradas a implementar mtodos que no
sero utilizados por elas. Quando uma interface propaga mtodos public void comer() {
utilizados por algumas classes, mas no aproveitados por outras, // comendo...
}
ocorre a subscrio forada. A interfaces como estas damos o nome }
de interfaces poludas. public class Gerente {
justamente disso que trata o Princpio da Segregao de Interfaces ITrabalhador trabalhador;
public void setTrabalhador(ITrabalhador trabalhador) {
(ISP), o qual afirma que os clientes no devem ser obrigados a im- this.trabalhador = trabalhador;
plementar interfaces que no utilizaro. Ao invs de uma interface }
public void gerenciar() {
poluda, o ideal seria fazer uso de vrias interfaces baseadas em
trabalhador.trabalhar();
pequenos grupos de mtodos, em que cada um deles atenderia a }
um determinado sub-mdulo. }
Para exemplificar a ideia do que seria uma interface poluda, Listagem 8. Exemplo de design flexvel ao utilizar ISP.
observe a Listagem 7. Esse cdigo nos mostra uma situao em
que a classe Gerente responsvel por gerenciar trabalhadores public interface ITrabalhador {
public void trabalhar();
de dois tipos: trabalhadores bsicos e trabalhadores excepcionais, }
que so aqueles que conseguem desempenhar mais atividades no
public interface IAlimentavel {
mesmo espao de tempo que os bsicos. Ambos os tipos, alm de
public void comer();
trabalharem, necessitam do seu devido intervalo para almoo. }
Porm a empresa evoluiu, e com isso surgiu a ideia de adicionar
public class Trabalhador implements ITrabalhador, IAlimentavel {
robs para tambm atuarem como trabalhadores. No entanto,
diferentemente dos demais trabalhadores, os robs no precisam public void trabalhar() {
// trabalhando...
se alimentar.
}
Mediante o design apresentado, surge o seguinte problema: as
classes referentes aos robs tambm precisariam implementar a public void comer() {
// comendo...
interface ITrabalhador, j que a mesma o contrato que define o }
comportamento de todos os tipos de trabalhadores da empresa. }
Contudo, ao procedermos dessa forma, os robs tambm iriam
public class TrabalhadorExcepcional implements ITrabalhador, IAlimentavel {
adquirir o mtodo comer() sem necessidade.
Ao manter o design dessa forma, alguns comportamentos no public void trabalhar() {
// trabalhando...
desejados podem acontecer, como resultados incorretos apresen-
}
tados por um relatrio, ao analisar, por exemplo, a quantidade de
refeies para os trabalhadores. public void comer() {
// comendo...
Para resolver o problema de design da Listagem 7, de acordo com }
a ISP, devemos separar a interface ITrabalhador em duas outras }
interfaces, tornando assim a implementao realmente flexvel.
public class Robo implements ITrabalhador {
Vejamos como fica o cdigo modificado na Listagem 8.
No novo design foi criada a interface IAlimentavel para contem- public void trabalhar() {
// trabalhando...
plar o mtodo comer(), que antes pertencia interface ITrabalhador. }
Agora, as classes referentes aos trabalhadores bsicos e excepcionais }

Edio 45 easy Java Magazine 17


Qualidade no cdigo com os princpios S.O.L.I.D.

implementam duas interfaces: ITrabalhador, que ficou apenas com Listagem 9. Exemplo de violao do DIP.
o mtodo trabalhar(); e IAlimentavel, que possui apenas o mtodo
public class Trabalhador {
comer(). Quanto s classes dos robs, elas s precisam implementar
a interface ITrabalhador, pois estes s iro trabalhar. public void trabalhar() {
A partir desse novo design a classe Robo no mais forada a //Trabalhando...
}
implementar o mtodo comer(), de forma que caso seja necessrio }
criar alguma funo especfica para robs, basta definir uma nova
interface; por exemplo, IRecarregavel, para recarregar() os robs public class Gerente {

aps um longo dia de trabalho. Trabalhador trabalhador;

Princpio da Inverso de Dependncias public void setTrabalhador(Trabalhador trabalhador) {


this.trabalhador = trabalhador;
A ideia deste princpio de design representada atravs da }
concepo de que classes de alto nvel no devem depender de
public void gerenciar() {
classes de baixo nvel, isto , elas no devem estar ligadas de forma
trabalhador.trabalhar();
direta, mas sim atravs de alguma abstrao. }
Em todo desenvolvimento de aplicaes, considerado que }
classes de baixo nvel so responsveis por implementar ope-
public class TrabalhadorExcepcional {
raes primrias e bsicas, como leitura de arquivos, acesso ao
disco, uso de protocolos de rede, etc. J as classes de alto nvel public void trabalhar() {
//Trabalhar muito mais
so aquelas responsveis por encapsular as lgicas complexas do }
sistema, como os fluxos do negcio. Nas arquiteturas de sistemas }
convencionais, componentes de baixo nvel so criados para serem
Listagem 10. Exemplo correto de uso do DIP.
consumidos por componentes de alto nvel, ou seja, as classes de
mais alto nvel so projetadas dependendo diretamente das de public interface ITrabalhador {
public void trabalhar();
mais baixo nvel para executar alguma tarefa.
}
Esta forte dependncia com os componentes de baixo nvel, no
entanto, acaba por limitar as oportunidades de reutilizao dos public class Trabalhador implements ITrabalhador {
public void trabalhar() {
componentes de alto nvel. Para evitar esse tipo de problema,
//trabalhando...
uma nova camada abstrata pode ser introduzida entre os nveis, }
separando as classes de alto nvel das de baixo nvel. Vale lembrar, }
contudo, que a camada abstrata no deve ser criada a partir dos public class TrabalhadorExcepcional implements ITrabalhador {
componentes de baixo nvel, e sim o contrrio: os componentes public void trabalhar() {
devem ser criados a partir da camada abstrata. //trabalhando...
}
Ainda de acordo com este princpio, o caminho para um design }
de componentes estruturados corretamente seria iniciar o desen-
volvimento a partir das classes de alto nvel para as de baixo nvel. public class Gerente {

Dessa forma teramos: Classes de Alto Nvel > Camada Abstrata > ITrabalhador trabalhador;
Classes de Baixo Nvel.
O exemplo da Listagem 9 mostra uma implementao que public void setTrabalhador(ITrabalhador trabalhador) {
this.trabalhador = trabalhador;
viola a ideia do IDP. Note que continuamos seguindo o mesmo }
caso dos trabalhadores de uma empresa. Neste cdigo, temos
public void gerenciar() {
a classe Gerente como sendo um componente de alto nvel e
trabalhador.trabalhar();
a classe Trabalhador como sendo de baixo nvel. No entanto, }
agora a empresa resolveu separar as classes trabalhadoras em }
trabalhadores comuns e trabalhadores excepcionais, e para isso
ser necessrio criar uma nova classe, que chamaremos de Tra-
balhadorExcepcional. Da forma como o design se encontra, para cada novo tipo de
Tomaremos como base que a classe Gerente, no exemplo pro- trabalhador uma nova referncia ser necessria, assim como uma
posto, seja a classe de alto nvel, pois ela ser responsvel por nova chamada para o mtodo trabalhar(), exclusivo de cada tipo
interagir com todas as classes que representaro os diferentes tipos de trabalhador, dever ser criada dentro do mtodo gerenciar()
de trabalhadores. De acordo com a implementao apresentada na da classe Gerente.
Listagem 9, teremos que alterar a classe Gerente para adicionar Devido a essas alteraes, podemos causar algum dano no
o novo tipo de trabalhador. previsto em alguma funcionalidade j existente da classe Gerente.

18 easy Java Magazine Edio 45


Nota
Autor
Ao respeitar o Princpio da Inverso de Dependncia (DIP) possvel reduzir o acoplamento e criar
Marcio de S. Justo de Oliveira
objetos reutilizveis de forma mais flexvel.
marcio.justo@gmail.com
formado em Criao e Gesto de Ambientes Internet pela
faculdade Estcio de S. Trabalha com Java h oito anos, tendo
Para resolver esse problema de design, devemos alterar essa classe desenvolvido sistemas para grandes clientes como Caixa Econmica
para que ela deixe de trabalhar diretamente com a classe concreta Federal, Petrobras e Bradesco Seguros. Atualmente desenvolvedor
Trabalhador e passe a ter uma interao mais abstrata. Para isso, snior na Capgemini Consulting, Technology and Outsourcing.
criaremos a interface ITrabalhador e esta dever ser implemen-
tada pela classe Trabalhador. A partir desta soluo poderemos
atuar com novos tipos de trabalhadores, bastando para isso que Links:
as novas classes tambm implementem ITrabalhador.
Assim, salvo que alguma alterao por parte da lgica de negcio Principles Of OOD.
http://butunclebob.com/ArticleS.UncleBob.PrinciplesOfOod
seja precisa, nenhuma outra mudana ser necessria em nossa
classe Gerente quando novos trabalhadores forem adicionados. Artima Developer.
Vejamos como fica essa implementao na Listagem 10. http://www.artima.com/designtechniques/
Um design de qualidade pode facilitar e muito a implementao
Desenvolvendo software slido - Java Magazine 79.
de cdigos reutilizveis e coesos. No entanto, para que isso ocorra,
http://www.devmedia.com.br/desenvolvendo-software-solido-java-magazine-79/16799
tambm importante que o cdigo seja claro e desprovido de
funcionalidades desnecessrias. Livros
Para alcanar esse cenrio, diversos so os conceitos que o de- Introduo Arquitetura e Design de Software, escrito por Paulo Silveira, Guilher-
senvolvedor precisa compreender. Entre esses conceitos esto os me Silveira, Srgio Lopes, Guilherme Moreira, Nico Steppat e Fbio Kung.
princpios S.O.L.I.D., que certamente fazem grande diferena na
hora de implementarmos o projeto com qualidade.

Edio 45 easy Java Magazine 19


POO: reusabilidade e eficincia em seu cdigo Parte 2

Programao Orientada a
Objetos (POO): reusabilidade
e eficincia em seu cdigo
Parte 2
Produza cdigo correto, gil e otimizado com os
poderosos recursos da linguagem Java
Este artigo faz parte de um curso Fique por dentro
Apesar da grande maioria das organizaes j adotar linguagens
orientadas a objetos, em muitas destas a programao ainda ocorre
na forma de grandes blocos de cdigo, ignorando as vantagens da

N
o primeiro artigo da srie, introduzimos o tema orientao a objetos. Sendo assim, esse artigo apresenta os princi-
Programao Orientada a Objetos e iniciamos pais recursos da linguagem Java relativos programao orientada
a explicao sobre os conceitos bsicas desse a objetos, habilitando o programador a obter cdigo reutilizvel e
paradigma. Aprendemos o que so classes e objetos, eficiente sem complicar suas implementaes, superando metodo-
conhecemos os modificadores de acesso e tambm o logias antigas, onde os programas so caracterizados por serem uma
conceito de herana, usando classes e interfaces. coleo de blocos de cdigo.
Neste artigo continuaremos nosso estudo sobre heran-
a, agora atravs de classes abstratas, e depois aprende-
remos sobre encapsulamento e polimorfismo, cobrindo tem a funo de manter o nome e o setor do produto, incluindo a
assim os principais conceitos da Orientao a Objetos quantidade em estoque.
na prtica com Java. Como pode-se observar na linha 3, a classe Produto decla-
rada como sendo abstrata pelo uso da palavra-chave abstract.
Herana usando classes abstratas Essa classe contm trs atributos (nome, setor e estoque
Classes abstratas so classes que no podem ser ins- linhas 5 a 7), de modo que os dois primeiros so informados
tanciadas diretamente e so definidas atravs da palavra no construtor (linhas 9 a 13), e o estoque inicia com zero.
chave abstract, empregada como modificador da classe. Os getters e setters para ambos os atributos so definidos nas
Alm disso, uma classe abstrata se comporta de forma linhas 15 a 29.
parecida com uma interface, pois uma classe abstrata J nas linhas 31 a 33 definido o mtodo toString(), que retorna
pode conter mtodos abstratos (sem implementao) uma descrio textual do produto, de forma a retornar uma men-
usando ponto-e-vrgula no lugar do corpo do mtodo e sagem com o nome e o estoque. Na linha 35 declarado o mtodo
a palavra-chave abstract como modificador destes. ajustaEstoque(), que pode ser utilizado pelas classes filhas para
importante notar que uma subclasse no abstrata de ajustar a varivel estoque.
uma classe abstrata pode ser instanciada normalmente, Ao final, na linha 39, declarada a assinatura do mtodo abs-
pois ela obrigada a implementar todos os mtodos trato entradaEstoque(), e na linha 41, o mtodo saidaEstoque().
abstratos da classe me. Como exemplo de classe abs- Observe que ambos so declarados com a palavra-chave abstract
trata, proposta a classe Produto na Listagem 1, que e no contm a declarao do corpo.

20 easy Java Magazine Edio 45


Listagem 1. Cdigo da classe abstrata Produto. durante a execuo, a cada passo impresso na tela o estoque
corrente.
01. package pkg.mercado;
02.
03. public abstract class Produto {
Listagem 2. Especializao da classe abstrata Produto: ProdutoFisico.
04.
05. private String nome;
01. package pkg.mercado;
06. private String setor;
02.
07. private int estoque;
03. public class ProdutoFisico extends Produto {
08.
04.
09. public Produto(String nome, String setor) {
05. public ProdutoFisico(String nome, String setor) {
10. this.nome = nome;
06. super(nome, setor);
11. this.setor = setor;
07. }
12. this.estoque = 0;
08.
13. }
09. public void entradaEstoque(int quantidade) {
14.
10. ajustaEstoque(quantidade);
15. public String getNome() {
11. System.out.println(Entrada de Estoque do Produto Fsico + getNome()
16. return nome;
12. + quantidade = [ + quantidade + ]);
17. }
13. }
18.
14.
19. public void setNome(String nome) {
15. public void saidaEstoque(int quantidade) {
20. this.nome = nome;
16. ajustaEstoque(-quantidade);
21. }
17. System.out.println(Sada de Estoque do Produto Fsico + getNome()
22.
18. + quantidade = [ + quantidade + ]);
23. public String getSetor() {
19. }
24. return setor;
20. }
25. }
26. Listagem 3. Teste para as classes abstratas.
27. public void setSetor(String setor) {
28. this.setor = setor; 01. package pkg.mercado;
29. } 02.
30. 03. public class TesteProdutos {
31. public String toString() { 04. public static void main(String[] args) {
32. return Produto nome = [ + nome + ] estoque = [ + estoque + ]; 05.
33. } 06. ProdutoFisico p1 = new ProdutoFisico(Notebook, Informtica);
34. 07. ProdutoFisico q1 = new ProdutoFisico(Mesa, Mveis);
35. public void ajustaEstoque(int quantidade) { 08.
36. estoque = estoque + quantidade; 09. p1.entradaEstoque(200);
37. } 10. System.out.println(p1.toString());
38. 11. p1.saidaEstoque(50);
39. public abstract void entradaEstoque(int quantidade); 12. System.out.println(p1.toString());
40. 13.
41. public abstract void saidaEstoque(int quantidade); 14. q1.entradaEstoque(1000);
42. } 15. System.out.println(q1.toString());
16. q1.saidaEstoque(500);
17. System.out.println(q1.toString());
18. }
Como a classe Produto no pode ser instanciada, ela no tem 19. }
utilidade sozinha. Portanto, ela precisa ser especializada. Com
o intuito de representar uma nova verso de Produto, criamos a
classe ProdutoFisico, responsvel por descrever qualquer produto Na linha 6 criado o produto fsico notebook. Em seguida, na
na loja fsica (veja a Listagem 2). linha 9, dada uma entrada de estoque de 200 unidades, e por
Note que a classe ProdutoFisico estende Produto (linha 3) e fim, na linha 11, so retiradas 50 unidades, levando a um total
define um construtor (linhas 5 a 7), informando para a superclas- de 150 notebooks, o que mostrado na Listagem 4 nas quatro
se os atributos nome e setor usando super (linha 6). O mtodo primeiras linhas.
entradaEstoque() definido nas linhas 9 a 13, sendo herdado Ainda na Listagem 3, linha 7, criado um segundo produto,
de Produto, e tem a funo de adicionar produtos ao estoque e a mesa. Em seguida, na linha 14, adicionado ao estoque 1000
imprimir na tela uma descrio textual da operao. mesas, e so retiradas 500 na linha 16, levando a um estoque final
De forma semelhante, o mtodo saidaEstoque() codificado de 500 mesas, o que fecha com o total mostrado na Listagem 4
nas linhas 15 a 19 remove uma certa quantidade de produtos nas quatro ltimas linhas.
do estoque e imprime na tela uma descrio da operao. Para
mostrar o funcionamento de ProdutoFisico, codificamos na Encapsulamento
Listagem 3 um exemplo onde so criados dois produtos fsicos O conceito de encapsulamento aplicado quando temos uma
distintos, em seguida adicionada uma quantidade em estoque classe e queremos que certos atributos e mtodos sejam mani-
e depois retirada outra quantidade. Para facilitar a compreenso pulveis apenas dentro da prpria classe, de forma a esconder a

Edio 45 easy Java Magazine 21


POO: reusabilidade e eficincia em seu cdigo Parte 2

implementao interna desta, prevenindo a utilizao incorreta Listagem 6. Segunda parte da classe Loja.
da mesma por objetos externos. Para que isso seja possvel, os
14. public String getApelidoLoja() {
mtodos internos so definidos como sendo privados. 15. return apelidoLoja;
Alm disso, necessrio implementar um conjunto de mtodos 16. }
que so acessveis de fora da classe, formando uma espcie de 17.
18. public void setApelidoLoja(String apelidoLoja) {
interface de acesso externa. Tais mtodos devem ser declarados 19. this.apelidoLoja = apelidoLoja;
como pblicos e, portanto, acessveis em qualquer classe da 20. }
aplicao. 21.
22. public void adicionarFuncionario(Funcionario funcionario) {
O encapsulamento muito til para esconder a implementao 23. funcionarios.add(funcionario);
interna das classes e se encaixa muito bem na criao de bibliotecas 24. }
25.
de software, implicando na criao de uma API de acesso externa
26. public void adicionarCliente(Cliente cliente) {
que esconde a complexidade do cdigo. 27 clientes.add(cliente);
Como exemplo de classe que segue o conceito de encapsulamen- 28. }
29.
to, foi apresentada a classe Produto na Listagem 1. Outra classe 30. public void realizarVenda(Vendedor vendedor, Cliente cliente,
criada seguindo os conceitos de encapsulamento a classe Loja, 31. Produto produto) {
que tem sua primeira parte declarada na Listagem 5. 32. adicionarVenda(cliente);
33. calcularComissaoVendedor(vendedor);
34. atualizarEstoque(produto);
Listagem 4. Resultados no console para o teste envolvendo as classes Abstratas. 35. }

Entrada de Estoque do Produto Fsico Notebook quantidade = [200] Listagem 7. Terceira parte da classe Loja.
Produto nome = [Notebook] estoque = [200]
Sada de Estoque do Produto Fsico Notebook quantidade = [50] 36. private void adicionarVenda(Cliente cliente) {
Produto nome = [Notebook] estoque = [150] 37. System.out.println(Compra adicionada para o cliente
Entrada de Estoque do Produto Fsico Mesa quantidade = [1000] 38. + cliente.getNome());
Produto nome = [Mesa] estoque = [1000] 39. }
Sada de Estoque do Produto Fsico Mesa quantidade = [500] 40.
Produto nome = [Mesa] estoque = [500] 41. private void calcularComissaoVendedor(Vendedor vendedor) {
42. System.out.println(Comisso calculada para o vendedor
Listagem 5. Primeira parte da classe Loja. 43. + vendedor.getNome());
44. }
01. package pkg.mercado; 45.
02. 46. private void atualizarEstoque(Produto produto) {
03. import java.util.ArrayList; 47. System.out.println(Atualizao de estoque para o produto
04. 48. + produto.getNome());
05. public class Loja extends PessoaJuridica { 49. }
06. 50. }
07. private String apelidoLoja;
08. private ArrayList funcionarios = new ArrayList();
09. private ArrayList clientes = new ArrayList();
10. Observe que os mtodos apresentados nessa listagem so priva-
11. public Loja(String nome, boolean habilitado, long CNPJ) { dos, e, portanto pertencem implementao interna da classe.
12. super(nome, habilitado, CNPJ);
13. }
Polimorfismo
Quando so definidas vrias especializaes diferentes para
Repare que a classe Loja possui trs atributos que seguem as uma mesma superclasse, ocorre que cada especializao pode
regras do encapsulamento, apelidoLoja, funcionarios e clientes, reimplementar os mtodos da superclasse de uma forma diferente.
declarados privados (linhas 7 a 9). Como Loja uma PessoaJuri- Assim, podemos ter uma coleo de objetos, mas cada um deles
dica, ela recebe no seu construtor os atributos nome, habilitado no precisa necessariamente implementar da mesma forma as
e CNPJ de PessoaJuridica (que so repassados ao construtor da operaes da superclasse.
superclasse) e seu atributo apelidoLoja. Na Listagem 6 apre- Dito isso, codificamos a classe ProdutoVirtual (Listagem 8),
sentada a segunda parte da classe Loja. que implementa os mtodos entradaEstoque() e saidaEstoque(),
Nesse cdigo encontramos os mtodos da API da classe Loja, provenientes de Produto (Listagem 1).
invocados no acesso externo s funcionalidades desta classe. Pri- Alm disso, ProdutoVirtual contm um atributo chamado link
meiro temos o getter e o setter do atributo apelidoLoja e em seguida (linha 5) e define o getter e o setter correspondentes (linhas 12 a 17),
os mtodos pblicos adicionarFuncionario() e adicionarCliente(). completando a declarao da classe.
Por ltimo, temos o mtodo pblico realizarVenda(), que recebe O conceito de polimorfismo est diretamente relacionado
como parmetro um vendedor, um cliente e um produto e chama sobrecarga de mtodos (overloading ou sobrescrita), que signi-
os mtodos privados adicionarVenda(), calcularComissaoVende- fica que uma classe filha pode sobrescrever a implementao
dor() e atualizarEstoque(), declarados na Listagem 7. dos mtodos da classe me, permitindo aos objetos da classe

22 easy Java Magazine Edio 45


filha apresentarem uma implementao diferente nos mtodos Note que nas linhas 20 a 30 dessa listagem apresentada uma
sobrecarregados. nova implementao dos mtodos originrios da classe Produto,
Como exemplo, a classe CreditoVirtual, que representa uma ou seja, ocorre o overloading. A fim de mostrar o funcionamento
moeda virtual, sobrescreve os mtodos entradaEstoque() e saida- do polimorfismo, criada uma classe executvel na Listagem 10
Estoque() de ProdutoVirtual na Listagem 9, especializando-os. que instancia cada uma das subclasses de Produto (introduzidas
anteriormente) e realiza a entrada e sada de estoque para cada
Listagem 8. Cdigo da classe ProdutoVirtual. instncia.

01. package pkg.mercado;


02. Listagem 10. Cdigo da classe de teste TesteProdutosPoli.
03. public class ProdutoVirtual extends Produto {
04. 01. package pkg.mercado;
05. public String link; 02.
06. 03. public class TesteProdutosPoli {
07. public ProdutoVirtual(String nome, String setor, String link) { 04. public static void main(String[] args) {
08. super(nome, setor); 05.
09. this.link = link; 06. ProdutoFisico p1 = new ProdutoFisico(Notebook, Informtica);
10. } 07. ProdutoFisico q1 = new ProdutoFisico(Mesa, Mveis);
11. 08. ProdutoVirtual r1 = new ProdutoVirtual(Editor de Imagens,
12. public String getLink() { 09. Loja Virtual, www...);
13. return link; 10. CreditoVirtual s1 = new CreditoVirtual(Editor de Texto,
14. } 11. Loja Virtual, www..., 100);
15.
12.
16. public void setLink(String link) {
13. p1.entradaEstoque(100);
17. this.link = link;
14. q1.entradaEstoque(200);
18. }
19. 15. r1.entradaEstoque(300);
20. public void entradaEstoque(int quantidade) { 16. s1.entradaEstoque(400);
21. ajustaEstoque(quantidade); 17.
22. System.out.println(Adio de Seriais de Produto Virtual + getNome() 18. vendaProduto(p1);
23. + quantidade = [ + quantidade + ]); 19. vendaProduto(q1);
24. } 20. vendaProduto(r1);
25. 21. vendaProduto(s1);
26. public void saidaEstoque(int quantidade) { 22. }
27. ajustaEstoque(-quantidade); 23.
28. System.out.println(Sada de Seriais de Produto Virtual + getNome() 24. private static void vendaProduto(Produto p) {
29. + quantidade = [ + quantidade + ]); 25. p.saidaEstoque(1);
30. } 26. System.out.println(p.toString());
31. } 27. }
28. }
Listagem 9. Cdigo da classe CreditoVirtual.

01. package pkg.mercado;


02. Nesse exemplo so criados diversos produtos, sendo dois
03. public class CreditoVirtual extends ProdutoVirtual { produtos fsicos (linhas 6 e 7), um produto virtual (linha 8) e
04.
05. public double valor;
um produto de crdito virtual (linha 10). Em seguida, ocorre a
06. entrada no estoque de uma quantidade distinta para cada pro-
07. public CreditoVirtual(String nome, String setor, String link, double valor) {
duto (linhas 13 a 16), chamando o mtodo entradaEstoque(). Por
08. super(nome, setor, link);
09. this.valor = valor; fim, ocorre a venda de uma unidade de cada um desses produtos
10. } criados (linhas 18 a 21), o que feito chamando o mtodo venda-
11.
12. public double getValor() { Produto(), declarado na classe exemplo (TesteProdutosPoli).
13. return valor; O mtodo vendaProduto() recebe um objeto da classe Pro-
14. }
15.
duto como parmetro para efetuar a venda de uma unidade
16. public void setValor(double valor) { dele (linha 25) e escreve o resultado na tela (linha 26). Como o
17. this.valor = valor;
parmetro produto pode ser qualquer especializao da classe
18. }
19. Produto, importante observar que ele pode ser pode ser filho
20. public void entradaEstoque(int quantidade) { de ProdutoFisico, ProdutoVirtual ou CreditoVirtual. O resul-
21. ajustaEstoque(quantidade);
22. System.out.println(Adio de Crditos Virtuais + getNome() tado da execuo desse cdigo mostrado na Listagem 11.
23. + quantidade = [ + quantidade + ]); Podemos constatar nas quatro primeiras linhas a adio de cada
24. }
25. produto ao estoque feita de uma maneira particular, usando o
26. public void saidaEstoque(int quantidade) { mtodo entradaEstoque(). Nas linhas restantes ocorre a sada
27. ajustaEstoque(-quantidade);
28. System.out.println(Pagamento de Crditos Virtuais + getNome()
de cada produto, feita tambm de uma maneira particular (de
29. + quantidade = [ + quantidade + ]); acordo com cada implementao de Produto), usando o mtodo
30. } vendaProduto().
31. }

Edio 45 easy Java Magazine 23


POO: reusabilidade e eficincia em seu cdigo Parte 2

cdigo, manuteno simplificada, facilidade para o crescimento


Listagem 11. Resultado da execuo do exemplo da Listagem 10.
da aplicao, entre outros. Enfim, a correta compreenso e uti-
Entrada de Estoque do Produto Fsico Notebook quantidade = [100] lizao da herana, do encapsulamento e do polimorfismo leva
Entrada de Estoque do Produto Fsico Mesa quantidade = [200]
Adio de Seriais de Produto Virtual Editor de Imagens quantidade = [300]
a uma programao mais eficiente e simples, viabilizando um
Adio de Crditos Virtuais Editor de Texto quantidade = [400] cdigo limpo, o que bom para voc, para os desenvolvedores
Sada de Estoque do Produto Fsico Notebook quantidade = [1] da empresa em que voc atua e para o cliente.
Produto nome = [Notebook] estoque = [99]
Sada de Estoque do Produto Fsico Mesa quantidade = [1]
Produto nome = [Mesa] estoque = [199]
Sada de Seriais de Produto Virtual Editor de Imagens quantidade = [1]
Produto nome = [Editor de Imagens] estoque = [299]
Autor
Pagamento de Crditos Virtuais Editor de Texto quantidade = [1] John Soldera
Produto nome = [Editor de Texto] estoque = [399]
johnsoldera@gmail.com
bacharel em Cincias da Computao pela UCS (Universidade
de Caxias do Sul), mestre em Computao Aplicada pela Uni-
Uma ltima observao que se quisermos fazer com que um sinos e cursa atualmente doutorado em Cincias da Computao pela
mtodo no possa mais ser sobrescrito, pode-se utilizar a palavra- UFRGS (Universidade Federal do Rio Grande do Sul). Trabalha com Java
chave final como modificador do mtodo. Alm disso, final pode h 12 anos e possui a certificao SCJP.
ser utilizado tambm como modificador de classe, para evitar
que uma classe seja especializada, impedindo assim a relao de
herana para novas classes. Links:
Os conceitos da orientao a objetos so muito teis para alavan-
Javadoc da plataforma Java SE 7.
car o desenvolvimento em projetos de software, pois em compara- http://docs.oracle.com/javase/7/docs/api/
o com outros paradigmas, possibilitam maior reusabilidade de

24 easy Java Magazine Edio 45


Desenvolva aplicaes
com Play! Framework
Aprenda a implementar sistemas web com
qualidade e facilidade

A Fique por dentro


tualmente, obter informaes precisas e em um
curto espao de tempo se tornou indispensvel
para que pequenas e grandes corporaes so- Neste artigo apresentaremos os recursos do simples e prtico Play
brevivam e se mantenham atualizadas em relao forte Framework. Para isso, demonstraremos na prtica a criao de um chat,
concorrncia do mercado. Com isso, a tecnologia tem se e como um importante complemento, utilizaremos conjuntamente
tornado cada vez mais presente nas empresas, trazendo as solues do protocolo WebSocket para realizar a comunicao em
inovaes que possibilitam suprir tal necessidade. Neste tempo real entre a aplicao e o servidor.
contexto, entre as inovaes mais recentes e de grande
destaque se encontra a tecnologia WebSocket.
WebSocket um recurso que permite a comunicao A facilidade na deteco e resoluo de erros durante o processo
em tempo real entre cliente e servidor atravs de uma de desenvolvimento;
nica conexo TCP. A conexo mantida durante todo A possibilidade de utilizao de qualquer biblioteca Java;
o tempo e ambos podem se comunicar quantas vezes for O uso da arquitetura MVC/RESTful.
necessrio, no necessitando de solicitaes adicionais
(os famosos requests), resultando assim em ganho de Sendo assim, com o intuito de demonstrar a praticidade de se
performance para a aplicao. Geralmente esta soluo desenvolver com os recursos fornecidos pelo Play!, e tambm
adotada em aplicaes que requerem troca de infor- visando de abordar um exemplo onde possamos fazer uso de We-
maes e atualizaes em tempo real, como o caso bSockets, desenvolveremos no decorrer deste artigo um chat.
de uma transmisso online, que ao inserir uma nova
postagem precisa que esta seja notificada a todos ins- Play Framework
tantaneamente, sem precisar que cada um dos clientes O Play! um framework open source utilizado para o desen-
solicite esta atualizao. volvimento de aplicaes Java e Scala. O seu objetivo facilitar a
Como as corporaes possuem a necessidade de obter implementao de solues web visando a produtividade, para
solues geis e com bom desempenho, os desenvolve- que todo processo seja gil e o menos desgastante possvel. Como
dores tambm possuem a uma importante necessidade: grande vantagem est o fato de trabalhar com o processo de Hot
dispor de boas solues que permitam desenvolver pro- Deployment, que possibilita ao desenvolvedor visualizar as alte-
jetos com praticidade e produtividade. Neste contexto raes sem a necessidade de recompilar o projeto manualmente.
surge o Play Framework, outra tecnologia que iremos Com Hot Deployment, o tempo gasto para recompilar o projeto e
abordar no decorrer do artigo. execut-lo novamente se resume apenas a um simples refresh na
O Play! vem chamando a ateno dos desenvolve- pgina. Outra caracterstica fornecida por este framework a pos-
dores justamente por facilitar o desenvolvimento de sibilidade de se trabalhar com o sistema de rotas, que simplifica o
aplicaes web em Java, no necessitando de muitas mapeamento entre URLs e os controladores da aplicao.
ferramentas e configuraes complexas para a imple-
mentao da soluo, nem mesmo sendo necessria a O que WebSocket?
utilizao de uma IDE. Alm disso, o Play consome Normalmente, quando uma aplicao web acessada por um
recursos mnimos de hardware, possibilitando assim browser, uma solicitao HTTP enviada para o servidor web
seu uso em equipamentos inferiores. Dentre as diver- responsvel por hospedar a pgina. Em seguida, o servidor web
sas vantagens de se utilizar este framework, podemos analisa o pedido e envia a resposta. Em alguns casos, o tempo de
destacar: resposta excedido devido grande quantidade de informaes

Edio 45 easy Java Magazine 25


Desenvolva aplicaes com Play! Framework

a serem processadas, causando lentido e


transtornos (ver Figura 1).
O objetivo do WebSocket viabilizar a
comunicao assncrona entre servido-
res e aplicaes web que necessitam de
informaes em tempo real, como sites
de previses do tempo, sites de aes e
investimentos, jogos online, etc.
Com o uso desta soluo a comunicao
se torna mais prtica e com menores chan-
ces de causar lentido, pois utilizado um
canal de comunicao bidirecional entre Figura 1. Comunicao entre cliente e servidor com HTTP e WebSocket
navegador e servidor, e ento ambos po-
dem enviar e receber diversas mensagens
entre eles sem ter a necessidade de enviar Com o Play!, disponibilizado o banco Nota
mltiplas requisies. de dados H2, que fica armazenado interna-
O arquivo build.sbt contm instrues para o gerenciamento
Ao adotar o tradicional protocolo HTTP, mente no framework. Porm, com a adoo
de um projeto com o Play! Framework, dentre elas; diretivas
dependendo da complexidade da aplica- desta opo, a cada vez que iniciarmos a
de verso e dependncias para recursos adicionais, como por
o, necessrio o envio e recebimento de aplicao as informaes nele contidas
exemplo, a dependncia do banco de dados MySQL.
diversas requisies, seja pela aplicao ou sero perdidas, pois este banco til para
servidor. Alm disso, realizar vrias requi- ambientes de teste e como teremos a neces-
sies resulta em queda de desempenho sidade que as informaes permaneam com a execuo de apenas um comando a
da aplicao e do servidor, exigindo maior armazenadas, adotaremos o MySQL. partir do Play Console, que vem juntamen-
processamento de informaes. Com a Concluda essa etapa, comearemos a te com o pacote do framework.
utilizao da API WebSocket, padroniza- desenvolver a sala do chat. Para esta ta- Apesar disso, e devido importncia
da pela W3C (Word Wide Web Consortium), refa criaremos as classes Chat, SalaChat das IDEs para os projetos, o Play! oferece
abre-se a possibilidade de implantarmos e Login, que tero suas funcionalidades suporte ao NetBeans, Eclipse e IntelliJ
os recursos do protocolo WebSocket no explicadas mais adiante. Alm disso, para IDEA. Assim, caso o desenvolvedor queira
desenvolvimento de solues web, redu- realizar alguns procedimentos em nosso trabalhar com os recursos do Play! em uma
zindo assim consideravelmente o nmero chat, como iniciar a seo do websocket destas IDEs, basta digitar no console os
de requisies trocadas. e enviar mensagens para os usurios ao comandos play eclipsify nomeProjeto para
teclar Enter, utilizaremos recursos do adaptar o projeto ao Eclipse, play netbean-
A aplicao exemplo JavaScript. sify nomeProjeto para adaptar ao NetBeans
No decorrer do artigo iremos abordar o Inicialmente, preciso que voc configu- e play idealize nomeProjeto para adapt-lo ao
desenvolvimento de um chat. Para isso, va- re seu ambiente de desenvolvimento com a IntelliJ IDEA.
mos criar duas pginas HTML: a primeira verso 6 ou superior do Java e navegadores Dito isso, para criar o projeto, abra a linha
sendo uma tela de login para que o usurio que suportem o protocolo WebSocket. de comando, acesse o diretrio no qual foi
possa se autenticar e entrar na sala do chat, Consulte na seo Links o site para verifi- extrado o framework, digite o comando
e a segunda para exibir esta sala, na qual o car se o seu navegador compatvel. play new juntamente com o nome do pro-
usurio poder se comunicar com outros Caso seu ambiente de desenvolvimento jeto e, em seguida, escolha a opo 2 (Java
membros. No processo de autenticao da j esteja pronto, o prximo passo realizar Application) para definir o tipo do projeto,
pgina inicial iremos realizar uma simples a instalao do Play! Para isso, basta bai- conforme demonstra a Figura 2.
consulta no banco de dados para averiguar xar o framework no site oficial do projeto Quando criamos um novo projeto,
se as informaes repassadas aos campos (veja o endereo na seo Links), extra-lo definida uma estrutura de diretrios
de login constam na tabela de usurios. em qualquer diretrio e adicionar o cami- para armazenar os arquivos da aplicao.
Desta forma, precisamos configurar a nho onde foi descompactado na varivel Com o Play! Framework, o modelo MVC
conexo com o banco de dados (neste caso PATH. definido como padro. Assim, ao nave-
o MySQL) e adicionar a sua dependncia gar pelos diretrios do projeto, na pasta
ao arquivo build.sbt para que o Play! con- Criando o projeto Play! app encontraremos trs subdiretrios:
siga se comunicar com ele. Tambm ser Diferentemente de outras tecnologias controllers, models e views, responsveis
necessrio criar a classe que far referncia que necessitam de uma IDE para que seja por armazenar os principais arquivos
tabela onde esto armazenados os regis- possvel o desenvolvimento de um projeto, da aplicao. Tais arquivos iro definir
tros de login. o Play! possibilita a criao da aplicao toda a regra e a parte visual da aplicao.

26 easy Java Magazine Edio 45


Feito isso, o prximo passo lo-
calizar o arquivo application.conf e
adicionar as informaes de conexo
com o banco de dados, como driver
de conexo, URL do JDBC, usurio e
senha, conforme a Listagem 2.

Criando a classe de Login


Informados os dados de conexo
no arquivo application.conf, criaremos
agora a classe Login, que ir estender a
classe Model para poder utilizar os re-
cursos de persistncia e consulta com o
banco de dados que so disponibiliza-
dos pelo ebean (BOX 1). A classe Login
ir conter todos os campos da tabela
na qual iremos buscar as informaes
Figura 2. Comandos necessrios para criao do projeto do usurio que deseja se conectar ao
chat. Sendo assim, nesta classe vamos
Nesta organizao, a parte visual deve ser armazenada no definir trs atributos: id, nome e senha. Aps isso, com o Model.
diretrio views, as classes Java que contm regras de negcio Finder, recurso que faz parte da classe Model (linhas 23 e 24), cria-
devem ser armazenadas na pasta model e, por ltimo, na pasta remos o objeto find, que ser utilizado para auxiliar na consulta.
controller estaro presentes os controladores que realizam a co- A Listagem 3 apresenta o cdigo da classe Login.
municao entre model e view.
Outro diretrio importante e sobre o qual devemos compreender Listagem 1. Cdigo do arquivo build.sbt.
o conf. Este armazena o arquivo application.conf, local onde so
01. name := projetochat
especificadas algumas configuraes do sistema, tais como dados 02.
de conexo com o banco de dados, e o arquivo routes, que guarda 03. version := 1.0-SNAPSHOT
a declarao das rotas, ou seja, neste arquivo so definidas todas 04.
05. libraryDependencies ++= Seq(
as URLs que podero ser acessadas pela camada view. 06. javaJdbc,
O arquivo routes por padro j vem com duas rotas definidas, 07. javaEbean,
08. cache,
a saber:
09. mysql % mysql-connector-java % 5.0.8 )
1) a rota responsvel por encaminhar a requisio do usurio ao 11.
acessar a aplicao para o mtodo index(), localizado na classe 12. play.Project.playJavaSettings
Application, que tambm criada automaticamente quando Listagem 2. Adicionando informaes de conexo com o banco de dados no
criamos o projeto Play!; e, arquivo application.conf.
2) a rota que indica o caminho para a pasta public, local onde so
01. db.default.url=jdbc:mysql://localhost/dbplay
armazenados arquivos de imagem, CSS e JavaScript. 02. db.default.user=usuario
03. db.default.pass=senha
Caso a sua tela esteja semelhante Figura 2, j possvel acessar 04. db.default.logStatements=true
05. ebean.default=models.*
a aplicao pelo navegador. Assim, aps executar o comando play
run no Play! Console, acesse pelo navegador o link localhost:9000/.
BOX 1. Ebean
Caso aparea a mensagem Your new application is ready, sinal
de que sua aplicao est em pleno funcionamento e portanto um gerenciador de objetos relacionais utilizado pelo Play! e que adere o JPA como padro. Para
podemos dar continuidade ao desenvolvimento do nosso chat. saber mais detalhes, verifique na seo Links a documentao do ebean.

Estabelecendo a conexo com o banco de dados Criando a sala do chat


Aps instalar o Play! e criar a estrutura do projeto conforme Neste passo, iniciaremos a construo da sala do chat, codifican-
explicado nos tpicos anteriores, localize o arquivo build.sbt do para isso a classe SalaChat, que ser a estrutura principal do
no diretrio raiz do projeto e insira a dependncia do conector nosso projeto. Nela, iremos implementar o mtodo responsvel
MySQL, conforme apresenta a Listagem 1. Com a dependncia por incluir o usurio no chat e o mtodo que realizar o envio
instalada, o Play! interpretar que a sua aplicao necessita deste de mensagens ao bate-papo. A Listagem 4 exibe o cdigo dessa
conector e o instalar quando o projeto for executado. classe.

Edio 45 easy Java Magazine 27


Desenvolva aplicaes com Play! Framework

Nessa listagem, utilizaremos as classes UntypedActor, Actor- Listagem 3. Cdigo da classe Login.
System e ActorRef providas pela API de concorrncia Akka, que
tambm propriedade da TypeSafe, mesma empresa detentora 01. package models;
02.
dos direitos do Play. Esta API de concorrncia adere ao modelo de 03. import javax.persistence.*;
atores (BOX 2), que visa aumentar o desempenho da aplicao e 04. import play.data.validation.Constraints;
05. import play.db.ebean.Model;
melhorar o tempo de resposta do sistema para o usurio.
06.
07. @Entity
BOX 2. Atores 08. @Table(name = login)
09. public class Login extends Model {
Resumidamente, atores so definidos pela prpria documentao do Akka como entidades que
10.
efetuam a comunicao entre si atravs da troca de mensagens. 11. private static final long serialVersionUID = 1L;
12.
13. @Id
Ao criarmos a classe SalaChat, estendemos a classe abstrata 14. @Column(name = id)
UntypedActor e, desta forma, possibilitamos a criao de um 15. private Long id;
ator. Em seguida, criamos de fato o ator, na linha 3. Para isso, 16.
17. @Column(name = name)
instanciamos a classe ActorSystem, que tem como objetivo criar 18. private String name;
e armazenar os atores, e logo aps o inicializamos, atravs da 19.
chamada ao mtodo actorOf(), na linha 4. 20. @Column(name = senha)
21. private String senha;
Feito isso, instanciamos o objeto Map para armazenar todos os 22.
usurios conectados no chat, definimos o mtodo entrarChat(), 23. public static Model.Finder<Long, Login> find = new Model.Finder
<Long, Login>(
responsvel por viabilizar a entrada dos membros na sala e pelo
24. Long.class, Login.class);
envio de uma mensagem informando que determinado usurio 25.
se conectou. 26. }

28 easy Java Magazine Edio 45


Listagem 4. Cdigo da classe SalaChat. Listagem 5. Cdigo da classe Chat

01. public abstract class SalaChat extends UntypedActor { package controllers;


02.
03. private static ActorSystem system = ActorSystem.create(chat); package controllers;
04. private static ActorRef defaultRoom = system.actorOf(Props.create
(SalaChat.class), chat); import play.mvc.*;
05. import com.fasterxml.jackson.databind.JsonNode;
06. private static Map<String, WebSocket.Out<JsonNode>> import views.html.*;
listaDeMembros = new HashMap<String, import models.*;
07. WebSocket.Out<JsonNode>>(); import play.api.data.Form.*;
08. import play.data.Form;
09. import views.html.helper.form;
10. public static void entrarChat(final String username, import views.html.*;
WebSocket.In<JsonNode> in,
11. WebSocket.Out<JsonNode> out) throws Exception{ public class Chat extends Controller {
12.
13. final DateFormat dateFormat = new SimpleDateFormat
(dd/MM/yyyy HH:mm); private static final Form<Login> loginForm = Form.form(Login.class);
14. final Date date = new Date();
15. public static Result login() {
16. Acesso acs = new Acesso(username, out); return ok(login.render(loginForm));
17. Object obj = (Object)ask(defaultRoom, joined, 1000); }
18.
19. listaDeMembros.put(acs.username, acs.channel); public static Result abreSalaChat(String username) {
20. return ok(chatRoom.render(username));
21. enviaMensagemTodos(acs.username, Entrou no Chat.
+ - + dateFormat.format(date)); }
22.
23. in.onMessage(new Callback<JsonNode>() { public static Result consultar() {
24. Form<Login> form = loginForm.bindFromRequest();
25. public void invoke(JsonNode event) { Login log = form.get();
26. Login newLogin = new Login();
27. Conversa talkInstance = new Conversa(username ,event.get(text).asText() );
28. if (!log.getName().equals(null) && !log.getSenha().equals(null)) {
29. newLogin = Login.find.where().eq(name, log.getName())
30. enviaMensagemTodos (username, talkInstance.getMensagem() + - .eq(senha, log.getSenha()).findUnique();
+ dateFormat.format(date)); }
31.
32. } if (log.getName().equals(newLogin.getName())
33. }); && log.getSenha().equals(newLogin.getSenha())) {
34.
35. } return Chat.abreSalaChat(log.getName());
36
37. public static void enviaMensagemTodos(String user, String text) { } else {
38. for(WebSocket.Out<JsonNode> lista: listaDeMembros.values()) {
39. ObjectNode evento = Json.newObject(); return Chat.login();
40. evento.put(user, user); }
41. evento.put(message, text);
42. lista.write(evento); }
43. }
44. } public static Result chatRoomJs(String username) {
45. } return ok(views.js.chatRoom.render(username));

}
Definimos tambm o mtodo enviaMensagemTodos(), entre as
public static WebSocket<JsonNode> entrarChat(final String username) {
linhas 47 e 44. Como o prprio nome indica, ele serve para enviar return new WebSocket<JsonNode>() {
mensagens a todos os membros do chat.
public void onReady(WebSocket.In<JsonNode> in,
Com a classe do ator definida na camada Model, nosso prximo
WebSocket.Out<JsonNode> out) {
passo criar a classe Chat no diretrio app/controller e nela escre-
vermos alguns mtodos que sero executados diretamente da try {
ChatRoom.entrarChat(username, in, out);
camada view. A Listagem 5 apresenta o cdigo da classe Chat.
} catch (Exception ex) {
O mtodo login() ter o objetivo de abrir a pgina de login quan- ex.printStackTrace();
do solicitado pela camada view. O mtodo abreSalaChat(), por sua }
}
vez, ir exibir a sala do chat aps o usurio logar no sistema. };
Para que seja possvel estabelecer a comunicao entre a ca- }
mada View e a camada Controller, preciso que os links que }

Edio 45 easy Java Magazine 29


Desenvolva aplicaes com Play! Framework

iro chamar os mtodos estejam devidamente configurados no Listagem 7. Cdigo da pgina login.html.
arquivo routes.conf, o qual explicamos no incio do artigo. Seu
contedo apresentado na Listagem 6. 01. @(loginForm : Form[models.Login])
02.
Por ltimo, o mtodo entrarChat() invocado quando qualquer 03. <div>
usurio entra na sala chat. no momento em que este mtodo 04. <div>
05. @helper.form(action=routes.Chat.consultar()) {
acionado que o WebSocket aberto. Neste momento, ressaltamos
06. <form>
que a comunicao entre as camadas View e a classe Chat s ser 07. <fieldset>
possvel se a rota for declarada no arquivo routes.conf, conforme 08. <legend>Login</legend>
09. <div>
exibe a Listagem 6.
10. <div>
11.
Listagem 6. Cdigo do arquivo routes.conf 12. @helper.inputText(loginForm(name), _label -> Nome: )
13. @helper.inputPassword(loginForm(senha), _label -> Senha: )
01. # Routes 14.
02. # This file defines all application routes (Higher priority routes first) 15. </div>
03. 16. </div>
04. GET / controllers.Chat.login() 17. }
05. GET /room/inicializachat controllers.Chat.inicializaChat(username) 18.
06. GET /room/abresalachat controllers.Chat.abreSalaChat(username) 19. <div>
07. GET /assets/javascripts/chatroom.js controllers.Chat.chatRoomJs(username) 20. <label for=singlebutton></label>
08. POST /consultalogin controllers.Chat.consultar() 21.
09. 22. <div>
10. 23. <button id=singlebutton name=singlebutton>Entrar</button>
11. # Map static resources from the /public folder to the /assets URL path 24. </div>
12. GET /assets/*file controllers.Assets.at(path=/public, file) 25. </div>
26. </form>
27. </div>
28. </div>
No cdigo apresentado esto especificadas as rotas, ou seja,
so definidos os mtodos que sero acionados quando houver
uma solicitao da camada View a determinada URL. Em cada
linha configuramos primeiramente se a chamada ser realizada
via GET ou POST, em seguida nomeamos a rota e por ltimo
especificamos o mtodo que ser executado ao acessar a rota
declarada. Como exemplo de uso das rotas, no cdigo da pgina
salachat.html, que ser apresentado mais adiante, utilizamos a
rota descrita na linha 5 para a inicializao do chat.

Criando o layout da aplicao


Conforme mencionado, a parte visual do nosso chat ser elaborada
em duas telas. Na primeira delas teremos a tela de login, e na segunda Figura 3. Exibio da pgina de login
teremos o chat propriamente dito. As Listagens 7 e 8 apresentam o
cdigo das pginas de login.html e salachat.html, respectivamente. Em seguida, informamos atravs da tag <script> a dependncia ao
No cdigo da Listagem 7, definimos na linha 1 que a pgina de arquivo salachat.js, onde implementamos algumas funes JavaS-
login ser um formulrio, e para a construo desse formulrio cript que auxiliaro no funcionamento do chat. Tais funes sero
informamos a classe Login, que contm os atributos que sero teis para inicializar o websocket e viabilizar o envio de mensagens
necessrios, no caso: id, nome e senha. Deve-se informar a classe para os demais membros com o pressionamento da tecla Enter,
Login porque ao invocar o mtodo consultar(), na linha 5, ser por exemplo. O contedo do arquivo salachat.js apresentado na
feita a pesquisa dos dados informados nos campos de login (linhas Listagem 9. A pgina da sala do chat apresentada na Figura 4.
12 e 13) e assim verificar se estes constam no banco de dados. Nesse cdigo, a conexo com o WebSocket aberta ao instan-
Ainda na linha 5, note que utilizamos a anotao @helper para ciarmos a classe WebSocket na linha 5. Logo aps, nas linhas
indicar que o mtodo consultar(), localizado em Chat, dever ser 7 a 12, temos a funo enviaMensagem(), que ao ser chamada
acionado no momento em que o usurio pressionar o boto para ir enviar a mensagem digitada pelo usurio a todos os demais
entrar no chat, e nas linhas 12 e 13 utilizamos esta mesma anotao membros conectados ao chat. A funo enviaMensagemEnter(),
para especificar o tipo de dados para os campos de nome e senha. como o nome indica, possibilita o envio de mensagens ao pres-
A pgina de login apresentada na Figura 3. sionar a tecla Enter. Por ltimo, temos a funo receiveEvent(),
Por sua vez, a Listagem 8 apresenta o cdigo da pgina salachat. que ser invocada sempre que um novo usurio entrar na sala de
html. Nela adicionamos o componente textarea, no qual o usurio chat. Aps ser invocada, ela enviar uma mensagem avisando a
poder digitar o que deseja enviar aos demais membros do chat. entrada do novo usurio.

30 easy Java Magazine Edio 45


Listagem 8. Cdigo da pgina salachat.html.

01. @(username: String)


02.
03. <html>
04. <h1>Usurio logado: @username</h1>
05.
06. <div id=onChat>
07. <div id=main>
08. <div id=messages></div>
09. <textarea id=talk></textarea>
10. </div>
11. </div>
12.
13. <div>
14. <scriptsrc=@routes.Assets.at(javascripts/jquery-1.9.0.min.js)
type=text/javascript></script>
15. <script type=text/javascript charset=utf-8 src=@routes.Chat.salachat
(username)>
16. </script>
17. </div> Figura 4. Exibio da sala do chat
18. </html>

Listagem 9. Cdigo do arquivo salachat.js


O desenvolvimento de solues web continua se reinventando.
01. @(username: String)
02. A cada dia surgem novas tecnologias simplificam a implementa-
03. $(function() { o destas solues. A partir de agora, para comear a desenvolver
04. aplicaes real time, tarefa at ento vista com bastante receio
05. var websocket = new WebSocket(@routes.Chat.inicializaChat(username).
webSocketURL(request)) por muitos desenvolvedores, basta empregar tecnologias simples
06. como WebSockets. E para garantir a agilidade e eficincia da pro-
07. var enviaMensagem = function() {
gramao, fazer uso de solues como o Play Framework. Sendo
08. websocket.send(JSON.stringify(
09. {text: $(#talk).val()} assim, continue os estudos nestas tecnologias. Atravs delas voc
10. )) conseguir criar sistemas web diferenciados para seus clientes.
11. $(#talk).val()
Bons projetos!
12. }
13.
14. function enviaMensagemEnter(e) { Autor
15. e.which = e.which || e.keyCode;
16. if(e.which == 13) { Luis Gustavo Souza
17. enviaMensagem()
18. }
os.luisgustavo@gmail.com
19. } Cursa Sistemas de Informao pela Universidade de Franca,
20. trabalhou como desenvolvedor no Grupo Amazonas e hoje
21. var receiveEvent = function(event) { desenvolvedor Java na Universidade de Franca. Gosta de estudar e
22. var data = JSON.parse(event.data)
trabalhar com tecnologias open source e atualmente tem como objetivo
23.
24. $(#onChat).show() obter a certificao OCA Java.
25.
26. var el = $(<div class=message><span></span><p></p></div>)
Links:
27. $(span, el).text(data.user)
28. $(p, el).text(data.message)
29. $(el).addClass(data.kind) Download do Play Framework.
30. if(data.user == @username) $(el).addClass(me) http://www.playframework.com/download
31. $(#messages).append(el)
32. Informaes de compatibilidade do WebSocket com os browsers.
33. } https://www.websocket.org/echo.html
34.
35. $(#talk).keypress(enviaMensagemEnter) Exemplos de uso de WebSockets.
36. websocket.onmessage = receiveEvent
37. })
https://www.websocket.org/demos.html

Contedo sobre o Ebean.


https://www.playframework.com/documentation/2.0/JavaEbean

Documentao do Ebean.
http://www.avaje.org/ebean/documentation.html

Edio 45 easy Java Magazine 31


Desenvolva aplicaes com Play! Framework

32 easy Java Magazine Edio 45

You might also like