aluno: Jorge Augusto Melegati Gonçalves
ano/sem: 2008/2o.
data do laboratório (num. da semana) : 07/08/2008 (2)
Introdução
Este laboratório tinha como objetivo uma maior aproximação dos alunos com uma implementação real, a partir do modelamento de uma máquina de estados, assim como o exercício dos padrões Observer e Command além de classes anônimas em Java.
Desenvolvimento
O problema consistia basicamente da implementação de uma interface proposta para a máquina de estados.
Classe StateMachine
Esta é a principal classe da implementação pois ela implementa a interface proposta.
A classe possui, como atributos, objetos da classe HashMap para criar uma espécie de array associativo tendo como chave o nome do evento/estado e valor o respectivo objetivo, dessa forma foi possível, de uma forma simples, obter os estados/eventos a partir do seu nome. Além disso, há referências para o estado inicial e o estado atual. Para implementar o padrão Observer, possui um Vector da interface Observer, o que será discutido mais adiante.
Classes UndefinedTransitionException, UndefinedStateException e UndefinedEventException
Essas classes representam as exceções lançadas pela nossa máquina de estados. A primeira é subclasse de Exception (exceção tratada) e as duas últimas são subclasses de RuntimeException (exceções não tratadas).
Esta configuração das classes de exceção foi um pouco modificada em relação a especificação por se encaixar melhor em requisitos mais importantes como a interface proposta para StateMachine.
Classes Event e State
Essas classes possuem estrutura semelhantes. A classe State tem um nome, uma referência a um método de estado (que pode ser passado para o construtor que aceita como parâmetro uma classe do tipo StateCommand (serão passadas classes anônimas)).
A classe Event tem, além do nome e do EventCommand, um HashMap para guardar as transições possíveis e um EventGuard, que são as cláusulas de guarda.
Classes EventCommand e StateCommand
Essas classes implementam as ações de evento e de estado. São classes abstratas, com o método abstrato execute(), e são as superclasses das classes anônimas instanciadas no momento de instanciação das classes Event e State. Elas representam o padrão Command pois encapsula a chamada a um método.
Interface EventGuard
Interface que representa as cláusulas de guarda. Também será utilizada através da instanciação de uma classe anônima através do métod setGuardToEvent().
Interface Observer
Interface responsável pela implementação do padrão Observer. Para isso, a classe StateMachine possui um Vector de Observadores, que podem ser registrados através do método addObserver(), que representam os observadores do seu estado, objetos que implementam essa interface impondo-lhe o método update(), que será chamado após cada mudança de estado da instância na qual estão registrados de StateMachine.
Testes
Para a realização dos testes, o código proposto foi modificado no que diz a suas classes de exceção (foram trocadas UndefinedStateError por UndefinedStateException e e mesmo para UndefinedEventError). Com essas alterações, o resultado dos testes é mostrado na seguinte figura.
Utilização da máquina de estados na situação proposta
Para continuar a série de testes da máquina, utilizou-se a aplicação proposta do Professor e da Turma. Inicialmente, testaram-se todas as transições possíveis para o Professor, o que está mostrado na figura a seguir. Todos os resultados concordaram com o esperado.
A seguir, testou-se a condição de guarda, com o professor ganhando milhões de dólares, o que evitou a saída do estado motivado, concordando com o esperado. A figura a seguir mostra o teste realizado.
Utilização de máquina de estados em uma situação
Buscando uma utilização prática da máquina de estados, encontrei uma muito interessante e que será util no desenvolvimento do projeto final da matéria.
A máquina de estados pode ser utilizada para trocar entre as telas de um jogo como apresentação, menu e jogo, com eventos relacionados a tecla Esc e Enter.
Simplificando o problma, resumiu-se o problema ao seguinte diagrama de fluxo de estados:
Para implementá-lo utilizou-se uma GUI bem simples que implementa a interface KeyListener e caso as teclas Esc ou Enter sejam pressionadas, disparas eventos na nossa máquina de estado, modificando um texto em um JLabel por essa GUI implementar a interface Observer da nossa máquina de estados.
O código-fonte referente a esta implementação está no arquivo lab3.2.rar.
Conclusão
Foi implementada a máquina de estados da forma especificada e os testes foram satisfatórios. A experiência adquirida foi muito variada pois expôs alguns elementos além dos já especificados como a API Java para listas, hashes, etc, pois exigiu-se a pesquisa sobre essas estruturas, e os conceitos de visibilidade e encapsulamento de classes internas de um pacote.
A necessidades de testes de softwares se tornou evidente nesse desenvolvimento, pois um problema grave só foi detectado na última etapa de testes (observação: o problema ocorreu na chamada ao StateCommand o que não foi revelado antes porque o código da classe de testes não verificava isso.)