Programação avançada – capitulo 8 – maquina de estados, exemplo1

Exemplo de uma maquina de estado, simples, usando as referências a um mecanismo de um elevador

Em que ficou:

Com:

package me_me_elevador;

import me_me_elevador.IU.Texto.UsaElevador;
import me_me_elevador.logica.Elevador;

public class Me_ME_elevador {
    public static void main(String[] args) {
        Elevador e = new Elevador();
        UsaElevador usaE = new UsaElevador(e); //interface com o utilizador
        usaE.corre();
    }
}
package me_me_elevador.IU.Texto;

import me_me_elevador.logica.*;
import me_me_elevador.util.IUUtil;

public class UsaElevador {

    //o interface com o utilizador, com o nosso elevador.
    private Elevador elevador;
    private boolean sair = false;

    public UsaElevador(Elevador elevador) {
        this.elevador = elevador;
    }

    public void corre() {
        while (!sair) {
            //saber em que estado estou
            IEstado estado = elevador.getEstado();
            if (estado instanceof RC) {
                iuRC();
            } else if (estado instanceof Andar1) {
                iuAndar1();
            } else if (estado instanceof Andar2) {
                iuAndar2();
            } else if (estado instanceof Andar3) {
                iuAndar3();
            }
        }
    }

    private void iuRC() {
        //opcoa 1
        //pedir ao utilizador: sair ou subir
        int opcao = IUUtil.getOpcao("Piso R/C", "Ir embora", "Subir");
        switch (opcao) {
            case 0:
                sair = true;
                break;
            case 1:
                //fazer evoluir a maquina de estados
                elevador.sobe();
                break;
        }
    }

    private void iuAndar1() {
        int opcao = IUUtil.getOpcao("Piso 1 andar","Descer", "Subir");
        switch (opcao) {
            case 0:
                //fazer evoluir a maquina de estados
                elevador.desce();
                break;
            case 1:
                //fazer evoluir a maquina de estados
                elevador.sobe();
                break;
        }
    }

    private void iuAndar2() {
        int opcao = IUUtil.getOpcao("Piso 2 andar","Descer", "Subir");
        switch (opcao) {
            case 0:
                //fazer evoluir a maquina de estados
                elevador.desce();
                break;
            case 1:
                //fazer evoluir a maquina de estados
                elevador.sobe();
                break;
        }
    }

    private void iuAndar3() {
        int opcao = IUUtil.getOpcao("Piso 3 andar","Descer");
        switch (opcao) {
            case 0:
                //fazer evoluir a maquina de estados
                elevador.desce();
                break;
        }
    }
}
package me_me_elevador.logica;

public class Andar1 extends Piso{

    @Override
    public IEstado sobe() {
        //altero de estado
        return new Andar2();
    }

    @Override
    public IEstado desce() {
        //altero de estado
        return new RC();
    }
}
package me_me_elevador.logica;

public class Andar2 extends Piso{

    @Override
    public IEstado sobe() {
        return new Andar3();
    }

    @Override
    public IEstado desce() {
        return new Andar1();
    }
}
package me_me_elevador.logica;

public class Andar3 extends Piso{

    @Override
    public IEstado sobe() {
        //fico no mesmo estado
       return this;
    }

    @Override
    public IEstado desce() {
        //altero de estado
        return new Andar2();
    }
}
package me_me_elevador.logica;

public class Elevador {
//é a maquina de estados, que faz alterar os estados
    IEstado estado;

    public Elevador() {
        //o estado incial//arranque é então:
        estado = new RC();
    }

    public IEstado getEstado() {
        return estado;
    }

    public void setEstado(IEstado estado) {
        this.estado = estado;
    }

    //podia ter outras informações, como o numero de pessoas
    //as luzes que estão ou não ligadas..
    //métodos que dão origem à mudança de estado
    public void sobe() {
        setEstado(estado.sobe()); //versão1
        //this.estado = estado.sobe();  //versão2
    }

    public void desce() {
        setEstado(estado.desce()); //versão1
        //this.estado = estado.desce();  //versão2
    }
}
package me_me_elevador.logica;

public interface IEstado {
    //acções comuns a cada uma dos estados:RC,andar1,andar2...
    //interface geral
    IEstado sobe();
    IEstado desce();
}
package me_me_elevador.logica;

public abstract class Piso implements IEstado {
    //classe para implementação default, sem alterar o estado
    //serve para simplifcar todas as outras
    @Override
    public IEstado sobe() {
        return this;
    }

    @Override
    public IEstado desce() {
        return this;
    }
}
package me_me_elevador.logica;

public class RC extends Piso{

    @Override
    public IEstado sobe() {
        //altero de estado
        return new Andar1();
    }

    @Override
    public IEstado desce() {
        //fico no mesmo estado
        return this; 
    }
}
package me_me_elevador.util;

import java.util.Scanner;

public class IUUtil {
    // v1
      public static int getOpcao(String question, String... options) {
        System.out.println(question);
        char[] ops = new char[options.length];
        for (int i = 0; i < options.length; i++) {
            char o = '\0';
            int c = 0;
            while (c < options[i].length()) {
                o = Character.toUpperCase(options[i].charAt(c));
                for (int j = 0; j < i; j++) {
                    if (ops[j] == o) {
                        o = '\0';
                        break;
                    }
                }
                if (o != '\0') {
                    break;
                }
                c++;
            }
            if (c >= options[i].length()) {
                return -1;
            }
            ops[i] = o;
            if (i > 0) {
                System.out.print(", ");
            }
            if (c > 0) {
                System.out.print(options[i].substring(0, c));
            }
            System.out.print("(" + ops[i] + ")" + options[i].substring(c + 1));
        }
        System.out.println();
        Scanner sc = new Scanner(System.in);
        while (true) {
            System.out.print("Option: ");
            char o = Character.toUpperCase(sc.nextLine().charAt(0));
            for (int i = 0; i < ops.length; i++) {
                if (o == ops[i]) {
                    return i;
                }
            }
        }
    }
}

No interface IEstado, são colocados todas as ações dos estados, mesmo que não façam sentido em alguns dos estados.
A class Piso, faz a implementação default de alguns dos estados para que não tenhamos que estar a repetir código nos diferentes estados.

Tags : , ,