tjt Posted August 9, 2017 Report Posted August 9, 2017 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 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. Quote
Active Members MrGrj Posted August 9, 2017 Active Members Report Posted August 9, 2017 Iti recomand https://codereview.stackexchange.com/ daca nu primesti nici-o parere p-aici Quote
gigiRoman Posted August 9, 2017 Report Posted August 9, 2017 (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 August 9, 2017 by gigiRoman Quote
Nytro Posted August 9, 2017 Report Posted August 9, 2017 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. Quote
Erase Posted August 9, 2017 Report Posted August 9, 2017 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; } Quote