Jump to content
tjt

Java - o parere despre implementarea unui state machine ?

Recommended Posts

Posted

Salut,

 

A trebuit azi la munca sa fac un state machine ca sa updatez UI bazat pe niste eventuri pe care le primesc. Am in jur de 50 de stari, 200 si ceva de eventuri si peste 800 de posibile tranzitii.

M-am lovit si in trecut de state machine, dar le-am evitat de fiecare data pentru ca nu mi-au placut niciodata.

 

Am implementat ceva la o scara mai mica folosind ca exemplu

 

fsm.png

 

ca sa vedeti cum am gandit totul:

 

import com.statemachine.test.events.Event;

public class StateMachine {
	
	private enum Event{
		GO,
		CWAIT,
		FINISH,
		RESET;
	}
	
	private interface IState{
		public IState process(Event e);
	}	
	
	private enum State implements IState{
		
		START("START"){
			
			@Override
			public IState process(Event e){
				printName();
				switch(e) {
					case GO:
						System.out.println("received GO. Return FIRE\n");
						return FIRE;
					case CWAIT:
						System.out.println("received CWAIT. Return WAIT\n");
						return WAIT;
					default:
						System.out.println("received something unexpected. Don't change\n");
						return this;
				}
			}
		},
		
		WAIT("WAIT"){
			
			@Override
			public IState process(Event e){
				printName();
				switch(e) {
					case GO:
						System.out.println("received GO. Return FIRE\n");
						return FIRE;
					case RESET:
						System.out.println("received RESET. Return START\n");
						return START;
					default:
						System.out.println("received something unexpected. Don't change\n");
						return this;
				}
			}
		},
		
		FIRE("FIRE"){
			
			@Override
			public IState process(Event e){
				printName();
				switch(e) {
					case FINISH:
						System.out.println("received FINISH. Return START\n");
						return START;
					case CWAIT:
						System.out.println("received CWAIT. Return WAIT\n");
						return WAIT;
					default:
						System.out.println("received something unexpected. Don't change\n");
						return this;
				}
			}
		};
		
		String name = null;
		private State(String name) {
			this.name = name;
		}
		
		public String getName() {
			return this.name;
		}
		
		public void printName() {
			System.out.println("State: " + this.name);
		}
	}
	
	public static void main(String[] args) {
		
		IState state = State.START;
		
		state = state.process(Event.RESET);
		state = state.process(Event.CWAIT);
		state = state.process(Event.GO);
		state = state.process(Event.CWAIT);
		state = state.process(Event.GO);
		state = state.process(Event.FINISH);
		state = state.process(Event.GO);
		state = state.process(Event.RESET);
		
	}
}

 

 

Output:

State: START
received something unexpected. Don't change

State: START
received CWAIT. Return WAIT

State: WAIT
received GO. Return FIRE

State: FIRE
received CWAIT. Return WAIT

State: WAIT
received GO. Return FIRE

State: FIRE
received FINISH. Return START

State: START
received GO. Return FIRE

State: FIRE
received something unexpected. Don't change

 

Programu merge, isi updateaza starile dar am impresia ca nu e tocmai ok implementarea si ca o sa ma trezesc peste 1-2 luni sa refac totul.

 

Vreo sugestie cum ar putea fi imbunatatit sau poate o alta abordare ?

 

Thanks.

Posted (edited)

Daca eventurile nu vin in ordinea in care ar trebui?

 

Nu stiu dc te ajuta, dar singurele programe la care am folosit fsm au fost doua parsere: https://1drv.ms/f/s!AhIgyEVSs5AknXtVVoDWSdGX7EuQ

1. Verifica niste coordonate geografice, le valida si genera o matrice in care colora cu rosu pozitiile valide. Exemplu input: (2,8)00,23(-1,13),(((7,3),)))[14,5)-----(10,5)

2. Un parser de paranteze: asta era putin mai complicat, am folosit stack puteai deschide trei tipuri de paranteze (, {, [ si verifica dc sunt inchise corect. De exemplu, (({}))[{}] este corect, ((())[] este gresit, in caz gresit trebuia mentionata pozitia in care crapa masina.

Deci ma gandesc ca in caz de eroare starea se reseteaza sau ceva...

Ai ambele rezolvari dc te intereseaza in linkul de mai sus. Implementarea e in c#. Cam asta e experienta mea cu masinile de stare finita. Dc mai dai detalii ar fi super.

Edited by gigiRoman
Posted

Pastrezi o referinta globala la "starea curenta" (un pointer de exemplu in C). Apoi, fiecare stare poate sa aiba un vector cu actiunile pe care sa le urmeze (pointer la functie in C) si evenimentele pe care le proceseaza. Cred ca HashMap ar ajuta aici, dar poti face un vector cu o structura cu Event/Pointer si la primirea unui eveniment il parcurgi si daca exista event definit, apelezi functia.

 

Sunt doar cateva idei generale de implementare. Am folosit state machine la Shellcode Compiler, dar nu stiu daca te ajuta cu ceva codul meu.

Posted

Daca nu vrei sa adaugi tu starile la initializarea clasei ai putea face in felul asta renuntand la implementarea enumeratiei, dar avand in vedere ca ai un numar mare de stari cred ca ar fi mai bine sa folosesti un dictionar pentru a salva starile si tranzactiile.

 

    private State mCurrentState;

    public State SetState(MEvent ev)
    {
      switch (ev)
      {
        case MEvent.Go:
          {
            Console.WriteLine("received GO. Return FIRE");
            mCurrentState = State.Fire;
            break;
          }
        case MEvent.CWait:
          {
            Console.WriteLine("received CWAIT. Return WAIT");
            mCurrentState = State.Wait;
            break;
          }
       	//case ... etc
        default:
          {
            Console.WriteLine("received something unexpected. Don't change");
            return mCurrentState;
          }
      }
      return mCurrentState;
    }

 

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.



×
×
  • Create New...