aluno: José Gerardo Arruda Junior
ano/sem: 2008/2o.
data do laboratório (num. da semana) : 16/10/2008 (3)
Introdução
Neste terceiro projeto de laboratório, foi desenvolvida uma biblioteca de máquina de estados com o intuito de exercitar uma modelagem OO para posterior uso em aplicações com fins práticos.
Com este fim, pôde-se aplicar os conceitos dos padrões de projeto Observer e Command, além de ser introduzir o conceito de classes anônimas, com a exemplificação de seu uso.
Desenvolvimento
A biblioteca foi desenvolvida de modo que sua interface pública estivesse toda na classe StateMachine. Os métodos das demais classes são, em sua maioria, privados e protegidos, de modo a favorecer o encapsulamento e esconder a complexidade da biblioteca ao usuário externo. Neste contexto, criaram-se 3 classes principais, que representam as principais entidades da aplicação: StateMachine, State e Event.
Como pode ser observado no diagrama de classes abaixo, preferiu-se não criar a classe Transition, que armazenaria os estados de origem e destino de cada transição. Ao invés disso, preferiu-se armazenar essa informação no HashMap transitions da classe Event, que armazena o próximo estado após a chamada do evento e tem como chave ou identifier o estado atual. Esta escolha de modelagem facilitou bastante o restante do código, visto que evitou-se a necessidade de busca em vetores para obter o próximo estado de uma transição.
Abaixo, apresentamos o diagrama de classes do pacote statemachine, gerado automaticamente no NetBeans. Em seguida, teceu-se breves comentários a respeito da implementação das principais classes da biblioteca.

Classe StateMachine
Na implementação desta classe também optou-se pela utilização de um HashMap para armazenamento de estados e eventos, com seus nomes funcionando como key do HashMap. Se fosse usada a classe Vector para este fim, teríamos que fazer buscas no vetor, tarefa esta bastante dispendiosa. Esta escolha fez ainda com que o código ficasse mais “limpo”.
Os métodos dessa classe foram implementados com a assinatura proposta e, com exceção de um deles, a descrição fornecida do laboratório foi suficiente para sua implementação. O método fireEvent() foi inicialmente implementado de uma forma que criava a máquina de estados proposta, mas que não atendia às especificações da classe de testes. Inicialmente os eventos estavam associados a apenas uma transição, podendo assim, existir eventos de mesmo nome (os métodos appendTransitionToEvent estavam inutilizados). A associação de várias transições a um evento é, de fato, bem mais elegante, pois evita a criação de várias condições de guarda para eventos de mesmo nome e favorece o reuso, mas esta descrição não havia ficado clara na descrição e só foi constatada com a execução da classe de testes.
Interessante o overload dos métodos dessa classe, que permitem a criação de estados com e sem ações, por exemplo. Novamente seguindo a idéia de “reuso”, chamou-se os métodos com menos parâmetros de entrada dentro daqueles de mesmo nome com mais parâmetros.
Classe State e Event
Em ambas classes, usou-se overload do contrutor, visto que estados e eventos podem ou não conter ações. Ressaltando o que já foi comentado, na classe Event armazenaram-se as transições de estado em um HashMap, de modo que a busca ao próximo estado é feita pelo nome do estado atual, chave do HashMap.
Classes StateCommand, EventCommand, EventGuard e Observer
Os códigos de tais classes foram fornecidos na descrição do laboratório e não sofreram quaisquer alterações.
Exceções
A superclasse das exceções solicitadas foram também estipuladas na descrição, de modo que a implementação e o uso de tais classes seguiu o que foi proposto, dispensando maiores comentários.
Classe de testes
Esta classe teve enorme importância no entendimento dos requisitos do projeto da biblioteca. Após a execução do teste, algumas modificações tiveram que ser realizadas a fim de que todos os 8 testes passassem.
Abaixo mostramos o resultado final, com os 8 testes passando. Uma observação: nesta classe as exceções estavam com nomes diferentes daqueles propostos, terminando com Error ao invés de Exception. Mudou-se ainda o nome do pacote de stateMachine para statemachine, pois não consegui renomear o pacote no NetBeans.

Exemplo de aplicação fornecido
O exemplo fornecido serviu para que testássemos o funcionamento de uma aplicação que faz uso de uma máquina de estados e para que aprendêssemos como é feita sua inicialização, visto que envolveu conceitos novos como o de classes anônimas.
A aplicação foi manuseada por meio dos eventos da turma, já que a idéia era que os eventos do professor, motivar e desmotivar, fossem chamados automaticamente e indiretamente, com o uso do padrão observer.
O código de manuseio gerado e o respectivo resultado estão apresentados abaixo:
Código do teste
package Exemplo; public class Main { public static void main(String[] args) { // TESTES COM O ESTADO DA TURMA E MUDANÇAS NO HUMOR DO PROFESSOR // A turma tem estado inicial "dormindo" e o professor, "motivado" Turma turma = new Turma(); Professor professor = new Professor(); turma.registerObserver(professor); System.out.println("TESTES COM O ESTADO DA TURMA E MUDANÇAS NO HUMOR DO PROFESSOR"); System.out.println(" "); System.out.println("A turma está " + turma.getState() + " e o professor está " + professor.getState()+ "."); System.out.println(" "); // Após a turma "usar_notebook", o professor fica desmotivado e faz prova ruim turma.fire("usar_note"); System.out.println(professor.fazerProva()); System.out.println("A turma está " + turma.getState() + " e o professor está " + professor.getState()+ "."); System.out.println(" "); // A turma presta atenção e motiva o professor, que prepara a aula com carinho turma.fire("ser_atenta"); System.out.println(professor.prepararAula()); System.out.println("A turma está " + turma.getState() + " e o professor está " + professor.getState()+ "."); System.out.println(" "); // A turma canceriza e o professor continua motivado e ganha milhoes! turma.fire("cancerizar"); professor.setGanhandoMilhoesDeDolares(true); System.out.println("A turma está " + turma.getState() + " e o professor está " + professor.getState()+ "."); System.out.println(" "); // A turma caga o pau, mas o professor não fica desmotivado enquanto ganha milhões turma.fire("usar_note"); turma.fire("dormir"); professor.setGanhandoMilhoesDeDolares(false); System.out.println("A turma está " + turma.getState() + " e o professor está " + professor.getState()+ "."); System.out.println(" "); // A turma continua a cagar o pau, e deixa o professor, não mais rico, irado! turma.fire("usar_note"); turma.fire("dormir"); System.out.println(professor.fazerProva()); System.out.println("A turma está " + turma.getState() + " e o professor está " + professor.getState()+ "."); System.out.println(" "); // A turma tenta se redimir, mas o professor nunca mais elaborará a aula com tanto carinho turma.fire("ser_atenta"); turma.fire("cancerizar"); System.out.println(professor.prepararAula()); System.out.println("A turma está " + turma.getState() + " e o professor está " + professor.getState()+ "."); System.out.println(" "); // A turma chuta o balde e sofre as consequencias na semaninha, fazendo uma prova sem noção que durou 10h! hehehe :] turma.fire("usar_note"); turma.fire("dormir"); System.out.println(professor.fazerProva()); System.out.println("A turma está " + turma.getState() + " e o professor está " + professor.getState()+ "."); System.out.println(" "); } }
Resultados
init:
deps-jar:
Compiling 1 source file to C:\Users\Junior\Documents\NetBeansProjects\StateMachine\build\classes
compile-single:
run-single:
TESTES COM O ESTADO DA TURMA E MUDANÇAS NO HUMOR DO PROFESSOR
A turma está dormindo e o professor está motivado.
Fiquei mais desmotivado!
Prova ruim, correção carteada
A turma está usando notebook e o professor está desmotivado.
Oba, fiquei mais motivado!
Aula preparada com carinho (5 horas)
A turma está prestando atenção e o professor está motivado.
Oba, fiquei mais motivado!
A turma está cancerizando nos labs e o professor está motivado.
A cláusula de guarda impediu a execução do evento!
A cláusula de guarda impediu a execução do evento!
A turma está dormindo e o professor está motivado.
Fiquei mais desmotivado!
Fiquei mais desmotivado!
nunca mais serei o mesmo!
Prova sem noção, média D
A turma está dormindo e o professor está irado.
Oba, fiquei mais motivado!
Oba, fiquei mais motivado!
Aula preparada com pressa (1 hora)
A turma está cancerizando nos labs e o professor está vacinado.
Fiquei mais desmotivado!
nunca mais serei o mesmo!
Fiquei mais desmotivado!
nunca mais serei o mesmo!
Prova sem noção, média D
A turma está dormindo e o professor está irado.
CONSTRUÍDO COM SUCESSO (tempo total: 1 segundo)
Aplicação desenvolvida
Para fazer uso da biblioteca criada, modelou-se os estágios da vida de um iteano. Os estágios modelados, representados pelos estados da máquina foram 6: pré-bixo, bixo, veterano, desligado, formado e rico.
O entendimento do funcionamento de tais estágios pode ser elucidado com do diagrama de estados abaixo e auxiliado pelas descrições que o seguem:

- Um iteano, ao ser criado, está no estágio inicial de “pré-bixo” e só consegue atingir o estado “bixo” com a ocorrência do evento “passar_no_vestibular”.
- O evento “passar_no_vestibular” só é executado se o iteano que o executa for inteligente (iteano.isClever = true). Um pré-bixo nasce sem ser inteligente.
- Os estados “bixo” e “veterano” compartilham dois eventos comuns: “pegar_I” e “desligar”. O evento “pegar_I” altera o histórico do iteano e é um evento estável, isto é, o estado não muda (diretamente) após sua execução. No entanto, o iteano é observado pelo reitor, que chama o evento “desligar” se o iteano pegar o sexto I.
- O iteano tem dois possíveis estados finais em sua vida: “desligado” e “rico”. O estado “rico” é alcançado depois que o iteano se “formar” e “esperar” um pouco.
- Alguns dos métodos e estados descritos acima possuem ações. O método “passar_no_vestibular” é o único que possui condição de guarda.
O diagrama de classe da aplicação está ilustrado abaixo. Como se pode observar optou-se por não se fazer uso da classe WithSM da aplicação exemplo, pois, em nossa aplicação, temos apenas uma máquina de estados (reitor não tem máquina de estados e funciona apenas como observer).

Abaixo está apresentado o código de testes para a aplicação. Testamos iteanos com dois estágios finais. Os resultados obtidos são mostrados em seguida.
Código do teste
package Aplicação; public class Main { public static void main(String[] args) { // TESTES COM ITEANO QUE SERÁ DESLIGADO Iteano iteano = new Iteano(); Reitor reitor = new Reitor(iteano); System.out.println("TESTES COM ITEANO QUE SERÁ DESLIGADO"); System.out.println(" "); // Chamada bloqueada pela condição de guarda iteano.fire("passar_no_vestibular"); // Iteano passou na segunda tentativa iteano.setClever(true); iteano.fire("passar_no_vestibular"); // O bixo pegou 2 I's e depois evoluiu pra veterano (O reitor está de olho...) iteano.fire("pegar_I"); iteano.fire("pegar_I"); iteano.fire("evoluir"); // O bixo pegou mais 4 I's e o reitor não perdoou iteano.fire("pegar_I"); iteano.fire("pegar_I"); iteano.fire("pegar_I"); iteano.fire("pegar_I"); System.out.println(" "); // Impressão do estado final System.out.println("Estado final: " + iteano.getState()); System.out.println(" "); System.out.println(" "); // TESTES COM ITEANO QUE SERÁ RICO!!! Iteano iteano2 = new Iteano(); iteano2.registerObserver(reitor); System.out.println("TESTES COM ITEANO QUE SERÁ RICO"); System.out.println(" "); // pré-bixão passou de primeira! iteano2.setClever(true); iteano2.fire("passar_no_vestibular"); // O bixo evoluiu pra veterano e pegou 1 I iteano2.fire("evoluir"); iteano2.fire("pegar_I"); // Se formou! E depois de uma breve espera... iteano2.fire("formar"); iteano2.fire("esperar"); System.out.println(" "); // Impressão do estado final System.out.println("Estado final: " + iteano2.getState()); } }
Resultados
init:
deps-jar:
Compiling 1 source file to C:\Users\Junior\Documents\NetBeansProjects\StateMachine\build\classes
compile-single:
run-single:
TESTES COM ITEANO QUE SERÁ DESLIGADO
A cláusula de guarda impediu a execução do evento!
Passei! Agora eu sou bixo!
Poxa.. Agora eu tenho 1 I's.
Poxa.. Agora eu tenho 2 I's.
Agora eu sou veterano!
Poxa.. Agora eu tenho 3 I's.
Poxa.. Agora eu tenho 4 I's.
Poxa.. Agora eu tenho 5 I's.
6o I ==> GAME OVER!
Fui desligado... :(
Estado final: desligado
TESTES COM ITEANO QUE SERÁ RICO
Passei! Agora eu sou bixo!
Agora eu sou veterano!
Poxa.. Agora eu tenho 1 I's.
Finalmente, estou formado!
E$$$tou Rico!
Estado final: rico
CONSTRUÍDO COM SUCESSO (tempo total: 0 segundos)
Conclusão
A aplicação foi bastante interessante. Foi realmente legal terminar e vê-la funcionando, mesmo com a sugação. Tive dificuldades no início para entender a proposta do trabalho. Não pra entender que seria modelada uma máquina de estados, mas sim de como esse modelo seria feito. Perdi algum tempo para entender os requisitos da biblioteca e alguns deles só puderam ser elucidados com a leitura do código de testes fornecido. Percebi que isso aconteceu com outros colegas também.
Os labs passados fiz no BlueJ. Neste, por conselho de um colega, resolvi usar o NetBeans e achei absurdamente bom! Além de auxiliar no entendimento do relacionamento entre as classes, o NetBeans fornece um auxílio grande no debug, permite a visualização (e aprendizado) dos métodos das bibliotecas, gera o diagrama de classes permitindo conferência com o modelo projetado e possui outras muitas funcionalidades que ainda não descobri. Acho importante que ao final do curso agente esteja bem familiarizado com um desses ambientes de projeto, até pra utilização em futuras matérias, estágios ou trabalhos. Fica a sugestão pra ser adotado no próximo ano.
Particularmente, atribuo o elevado número de melações à necessidade de dedicação exclusiva ao lab por algumas tardes ou noites devido sua extensão e quantidade de conceitos. Do ponto de vista de alguém que teve seu primeiro contato com Java neste semestre, prefiro práticas pequenas e constantes.
Por fim, acredito que este lab tenha substituído uns 3 não só no tempo, mas também em quantidade de aprendizado. O saldo foi positivo.





