Lab3 Fabio Imada

aluno: Fabio Imada
ano/sem: 2008/2o.
data do laboratório (num. da semana) : 09/10/2008 (2)

Introdução

Neste laboratório foi projetada uma máquina de estados a partir de sua interface pública. Desse modo foi necessário modelar a aplicação para que esta cumprisse com determinados requisitos.
Como a interface pública da máquina de estados já havia sido definida e testada, foi interessante notar o forçado encapsulamento do pacote. Todas as funcionalidades desejáveis para o usuário já estavam definidas, restando ao desenvolvedor projetar apenas o mecanismo interno que realizaria tais funções.

Desenvolvimento

O desenvolvimento foi realizado em IDE NetBeans em torno da interface pública da classe StateMachine.
Baseando-se nas assinaturas dos métodos, o corpo dos métodos foram escritos.
Ao longo do código, foi surgindo a necessidade de novas classes e funções. Como estes não faziam parte da interface pública, o acesso para eles foi definido como package-protected (uma vez que seriam utilizados dentro do pacote). Alguns outros foram definidos como private, visto que só havia necessidade de utilizá-los dentro da própria classe (como as variáves de instância, por exemplo).
Surgiu então a necessidade de modelar, através de um diagrama de classes, a interação das novas classes entre si e com a StateMachine. O resultado obtido após algumas tentativas frustradas foi o diagrama de classes abaixo:

diagramaNBSimplificado.jpg
Figura 1. Diagrama de Classes Simplificado

Desse modo, foi definido parcialmente uma interface para as novas classes e repetiu-se o processo de desenvolver a classe sobre a sua interface.
Segue abaixo os códigos que foram mais trabalhados, alguns como a classe abstrata StateCommand não foram citados por ser análogo ao EventCommand que foi dado.

++Classes

  • Classes de Erro

As classes de erro foram implementadas automaticamente pelo NetBeans:

package stateMachine;
public class UndefinedStateError extends RuntimeException
{
    public UndefinedStateError() {
    }
    public UndefinedStateError(String msg) {
        super(msg);
    }
}
  • Classe Event
package stateMachine;
import java.util.Vector; 
class Event
{
    private String name;
    private StateMachine sm;
    private Vector<EventCommand> ecList = new Vector<EventCommand>();
    private Vector<EventGuard> egList = new Vector<EventGuard>();    
    Event(StateMachine sm,String name){
        this.name=name;
        this.sm=sm;
    }   
    void addEventCommand(EventCommand ec){
        ecList.add(ec);
    }
    void addEventGuard(EventGuard g) {
        egList.add(g);
    }   
    boolean checkEventGuard(){
        boolean teste=true;
        if(egList!=null){
            for(EventGuard eg:egList){
                if(eg.shouldPerform()==false) teste=false;
            }
            return teste;
        }
        else return true;
    }
    String getName() {
        return name;
    }    
    void execute(String name){
        if(ecList!=null)
            for(EventCommand ec:ecList)
                ec.execute(name);
    }
}
  • Classe Transition
package stateMachine;
class Transition {
    private Event fireEvent;
    private State nextState;
    Transition (Event event,State state){
        fireEvent=event;
        nextState=state;
    }
 
    Event getEvent(){
        return fireEvent;
    }
    State getState(){
        return nextState;
    }
}
  • Classe State
package stateMachine; 
import java.util.*;
class State
{
    private String name;
    private Vector<Transition> transitionList = new Vector<Transition>();
    private StateMachine sm;
    private Vector<StateCommand> scList = new Vector<StateCommand>();    
    State(StateMachine sm,String name){
        this.name=name;
        this.sm=sm;
    }    
    void addTransition(String eventName,String nextState){
        try{
            Event event = sm.findEvent(eventName);
            State state = sm.findState(nextState);
            Transition transition = new Transition(event,state);
            transitionList.add(transition);
        }
        catch(UndefinedStateError e){
        }catch(UndefinedEventError e){
        }
    }    
    void addStateCommand(StateCommand sc){
        scList.add(sc);
    }    
    String getName(){
        return name;
    }
    State findTransition(Event eventFired) throws UndefinedEventError{
        for(Transition t : transitionList){
            if(eventFired == t.getEvent())return t.getState();
        }
        throw new UndefinedEventError("Undefined transition.");
    }
    void execute(){
        if(scList!=null){
            for(StateCommand sc : scList)
                sc.execute();
        }
    }
}
  • Classe StateMachine
package stateMachine;
import java.util.*;
public class StateMachine implements Subject
{
    /*-----------------------Variaveis de instancia----------------------*/
    private Vector<Observer> observerList =new Vector<Observer>();
    private Vector<State> stateList = new Vector<State>();
    private Vector<Event> eventList = new Vector<Event>();
    private State state;
 
    /*----------------------Comportamento observavel---------------------*/
    public void registerObserver(Observer observer){
        observerList.add(observer);
    }
    public void notifyObservers(){
        for(Observer observer : observerList){
            observer.update(this,state.getName());
        }
    }
 
    /*---------------Metodos para definicao da maquina-------------------*/
    public void createState(String name){
        State newState = new State(this,name);
        stateList.add(newState);
        if(state==null)state=newState;
    }
    public void createState(String name, StateCommand onEnter){
        this.createState(name);
        try{
            State editState = this.findState(name);
            editState.addStateCommand(onEnter);
        }catch(UndefinedStateError e){}
 
    }
    public void setInitialState(String name){
        try{
            state = this.findState(name);
        }catch(UndefinedStateError e){}
    }
    public void createEvent(String name, String from, String to){
        Event newEvent = new Event(this,name);
        eventList.add(newEvent);
        try{
            State editState = this.findState(from);
            editState.addTransition(name, to);
        }
        catch(UndefinedStateError e){
            System.out.println("Undefined State in State Machine");
        }
    }
    public void createEvent(String name, String from, String to,  EventCommand onSuccess){
        this.createEvent(name,from,to);
        try{
            Event editEvent = this.findEvent(name);
            editEvent.addEventCommand(onSuccess);
        }catch(UndefinedEventError e){}
    }
 
    public void createEvent(String name, String[] from, String to){
        for(String fromState : from){
            this.createEvent(name,fromState,to);
        }
    }
    public void createEvent(String name, String[] from, String to, EventCommand onSuccess){
        for(String fromState : from){
            this.createEvent(name,fromState,to,onSuccess);
        }
    }
    public void appendTransitionToEvent(String event, String fromState, String toState){
        try{
            State editState = findState(fromState);
            editState.addTransition(event,toState);
        } 
        catch(UndefinedStateError e){
 
        }
    }
    public void appendTransitionToEvent(String event, String[] fromState, String toState){
        for(String from : fromState){
            appendTransitionToEvent(event,from,toState);
        }
    }
    public void setGuardToEvent(String event,EventGuard g){
        try{
            Event editEvent = findEvent(event);
            editEvent.addEventGuard(g);
        }
        catch(UndefinedEventError e){}
    }
 
    /*---------------Metodos para execucao da maquina-------------------*/
    public boolean fireEvent(String name) throws UndefinedTransitionException{
        try{
            Event event = findEvent(name);
            if(event.checkEventGuard()){
                State nextState = state.findTransition(event);
                previousState = state.getName();
                state = nextState;
                state.execute();
                event.execute(previousState);
                for(Observer obs : observerList){
                    obs.update( this ,state.getName() );
                }
            }
            else{
                for(Observer obs : observerList){
                    obs.update( this ,state.getName() );
                }
                return false;
            }
        }catch(UndefinedEventError e){
            throw new UndefinedTransitionException("Undefined event in state.");
        }
        return true;
    }
 
    /*--------------Metodos auxiliares (package-protected)----------------*/
    State findState(String stateName) throws UndefinedStateError{
        for(State testState : stateList){
            if(stateName.equals(testState.getName() ) ){
                return testState;
            }
        }
        throw new UndefinedStateError("Undefined state.");
    }
    Event findEvent(String eventName) throws UndefinedEventError{
        for(Event testEvent : eventList){
            if(eventName.equals(testEvent.getName() ) ){
                return testEvent;
            }
        }
        throw new UndefinedEventError("Undefined event.");
    }
}

Diagrama de Classes Final

Em BlueJ:

diagramaBlueJSimplificado.jpg
Figura 2. Diagrama de Classes no BlueJ

E em NetBeans:

diagramaNB.jpg
Figura 3. Diagrama de Classes no NetBeans

Teste do Pacote stateMachine

testStateMachineNB.jpg
Figura 4. Teste de funcionamento do pacote

Teste Professor-Turma

Classe

  • testProfessorWithSM
import java.io.Console;
public class testProfessorWithSM
{
    public static void main(String[] args){
        Console c = System.console();
        Professor prof = new Professor();
        Turma turma = new Turma();
        turma.registerObserver(prof);
        String teste;
        do{
            teste = c.readLine("O professor esta recebendo milhões? ");
            if(teste.equals("s")){
                c.printf("O professor nunca fica desmotivado!\n");
                prof.setGanhandoMilhoesDeDolares(true);
            }
            else prof.setGanhandoMilhoesDeDolares(false);
            String event = c.readLine("O que a turma ira fazer? ");
            turma.fire(event);
            c.printf( prof.fazerProva() + "\n" + prof.prepararAula() );
            c.printf("\n");
            teste = c.readLine("Continuar? ");
            c.printf("\n");
        }while( teste.equals("s") );
    }
}

Resultado

O professor esta recebendo milhões? s
O professor nunca fica desmotivado!
O que a turma ira fazer? dormir
Prova com noção
Aula preparada com carinho (5 horas)
Continuar? s

O professor esta recebendo milhões? n
O que a turma ira fazer? dormir
Fiquei mais desmotivado!
Meu estado agora Ú desmotivado
Prova ruim, correção carteada
Aula preparada com pressa (1 hora)
Continuar? s

O professor esta recebendo milhões? n
O que a turma ira fazer? usar_note
Fiquei mais desmotivado!
nunca mais serei o mesmo!
Meu estado agora Ú irado
Prova sem noção, média D
Aula jogada (5 min)
Continuar? s

O professor esta recebendo milhões? n
O que a turma ira fazer? cancerizar
Oba, fiquei mais motivado!
Meu estado agora Ú vacinado
Prova ruim, correção carteada
Aula preparada com pressa (1 hora)
Continuar? n

Teste Rancho

Diagrama de Estados

diagEstados.jpg
Figura 5. Diagrama de Classes de Rancho

Classes

  • WithSM (idem teste Professor-Turma)
  • Rancho
public class Rancho extends WithSM implements stateMachine.Observer
{
    public Rancho() {
        super();
        setUpSM();
        sm.registerObserver(this);
    }
    private boolean comiDobradinha = false;
    public boolean euComiDobradinha(){
        return comiDobradinha;
    }
    public void setComiDobradinha(boolean is){
        comiDobradinha = is;
    }
    public void update(stateMachine.Subject sm, String newStateName) {
        System.out.println("Eu vou " + newStateName);
    }
    private void setUpSM() {
        //criando estados
        sm.createState("comer no rancho",new stateMachine.StateCommand(sm){
            public void execute(){
                System.out.println("Vale o esforco pra ir pro kart!");
            }
        });
        sm.createState("comer no COCTA",new stateMachine.StateCommand(sm){
            public void execute(){
                System.out.println("O rancho tah osso!!!");
            }
        });
        sm.setInitialState("comer no COCTA");
        //evento carne em cubos
        sm.createEvent("carne em cubos", "comer no rancho", "comer no COCTA");
        sm.appendTransitionToEvent("carne em cubos","comer no COCTA","comer no COCTA");
        //evento dobradinha
        sm.createEvent("dobradinha", "comer no rancho", "comer no COCTA", new stateMachine.EventCommand(sm) {
            public void execute(String previousState) {
                setComiDobradinha(true);
                System.out.println("Nunca mais serei o mesmo!!!");
            }
        });
        sm.appendTransitionToEvent("dobradinha", "comer no COCTA", "comer no COCTA");
        //Event medalhao de file mignon
        sm.createEvent("medalhao de file mignon","comer no COCTA","comer no rancho");
        sm.appendTransitionToEvent("medalhao de file mignon","comer no rancho","comer no rancho");
        sm.setGuardToEvent("medalhao de file mignon", new stateMachine.EventGuard(){
            public boolean shouldPerform(){
                return !euComiDobradinha();
            }
        });
    }
}
  • testRanchoWithSM
import java.io.Console;
public class testRanchoWithSM
{
    public static void main(String[] args){
        Console c = System.console();
        Rancho rancho= new Rancho();
        String teste;
        do{
            c.printf("O que tem no rancho hoje?\n");
            c.printf("\t1. Medalhao de file mignon\n");
            c.printf("\t2. Carne em cubos\n");
            c.printf("\t3. Dobradinha\n");
            teste = c.readLine();
            int numero = Integer.parseInt(teste);
            switch(numero){
                case 1: rancho.fire("medalhao de file mignon"); break;
                case 2: rancho.fire("carne em cubos"); break;
                case 3: rancho.fire("dobradinha"); break;
                default: rancho.fire("carne em cubos"); break;
            }
            teste = c.readLine("Continuar? ");
            c.printf("\n");
        }while( teste.equals("s") );
    }
}

Resultado

O que tem no rancho hoje?
1. Medalhao de file mignon
2. Carne em cubos
3. Dobradinha
1
Vale o esforco pra ir pro kart!
Eu vou comer no rancho
Continuar? s

O que tem no rancho hoje?
1. Medalhao de file mignon
2. Carne em cubos
3. Dobradinha
2
O rancho tah osso!!!
Eu vou comer no COCTA
Continuar? s

O que tem no rancho hoje?
1. Medalhao de file mignon
2. Carne em cubos
3. Dobradinha
3
Nunca mais serei o mesmo!!!
O rancho tah osso!!!
Eu vou comer no COCTA
Continuar? s

O que tem no rancho hoje?
1. Medalhao de file mignon
2. Carne em cubos
3. Dobradinha
1
Eu vou comer no COCTA
Continuar? n

Conclusão

A abordagem poderia ter sido menos apressada, pois isso economizaria tempo quando foi necessário modelar o diagrama de classes.
Do modo como foi feito, o entendimento do programa foi acompanhando o desenvolvimento da classe StateMachine, e por isso foi necessário reajustar o modelo diversas vezes para que este se adequasse à proposta.
Foi interessante notar que houve uma preocupação maior com o encapsulamento do pacote neste laboratório porque pela primeira vez foi utilizada uma interação entre pacotes, justificando o uso da permissão package-protected.
OBS. Após ver outros relas, foi adicionado a possibilidade de haverem múltiplos EventGuard e EventCommand por Event; e múltiplos StateCommand por State.

Códigos do Laboratório

Add a New Comment
Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License