Reduce if else statement in my ussd application - java

I have a ussd application where I generate an interface and with predefined options e.g 1. my account 2. transactions 3. bill enquiry. the user keys in either 1 or 2 or 3 or any other predefined option on their handset. now since the input from all interfaces is the same values, to keep track of the user's progress i have states i set each time a user navigates to a certain interface. now my problem is the states are becoming too many I have about 30 states and the if else statement is starting to look like one big ball of spaghetti plus not forgetting this approach is not scalable. any one can help me do a better design probably one that's scalable.
if (state == 35) {//exit application
a = mm.exit(uid);
out.println(a);
} else if (state == 3) {
a = view.main_menu_nav(uid, value.trim());
out.println(a);
} else if (state == 4) {
a = view.my_account(uid);
out.println(a);
} else if (state == 5) {
a = view.my_account_nav(uid, value.trim());
out.println(a);
} else if (state == 6) {
String value = USSD_STRING;
a = view.transaction_nav(uid, value.trim());
out.println(a);
} else if (state == 7) {
a = view.deactivate_nav(uid, value.trim());
out.println(a);
}

In your example snippet, there's repetition of out.println(a) in each clause of the if, you can simplify the code by moving out.println(a) outside of the if. You could also use a switch instead of an if.
Neither of these ideas fundamentally improve the design, however.
I would suggest you look at the "State" design pattern. Essentially, you have a separate object for each state that knows how to handle interactions in that state, and an outer container that receives events, holds a reference the current state object, and delegates the events to it.
A second (orthogonal) suggestion is to name your methods to reveal intentions—i.e. behavior. The method deactivate_nav() is OK, but my_account(uid) does not say what the method does.
It's hard to give specific advice without more information on your specific problem.

You can use a Map and let the key be the state, the value is an object of an interface, e.g. StateAction which provides a proper method which you then call:
StateAction action = stateActions.get(state);
action.execute();
The interface would be defined as
interface StateAction
{
void execute();
}
The map can be filled programmatic:
stateActions.put(35, new StateAction
{
public void execute()
{
//exit application
YourType a = mm.exit(uid);
out.println(a);
}
});
stateActions.put(3, new StateAction
{
public void execute()
{
YourType a = view.main_menu_nav(uid, value.trim());
out.println(a);
}
});
// and so on ...
It's also possible to create a class for your action and let it implement the interface:
class AccountHandler implements StateAction
{
// ...
public void execute()
{
YourType a = view.my_account(uid);
out.println(a);
}
// ...
}
Add this with
stateActions.put(4, new AccountHandler());

Related

How to get all events in wikidata

I am using the wikidata toolkit and I want to get a list of all events.
I wrote a EntityDocumentProcessor, where I want to filter for the events out of my dump. Well I know that the event document has the id Q1190554 and that I have to somehow check if the instance of the current itemDocument is an "instance of" (P31) of an event.
#Override
public void processItemDocument(ItemDocument itemDocument) {
boolean isEvent = false;
for (StatementGroup statementGroup : itemDocument.getStatementGroups()) {
switch (statementGroup.getProperty().getId()) {
case "P31": // P31 is "instance of"
isEvent = containsValue(statementGroup, filterClass);
break;
case "P279": // P279 is "subclass of"
if (!isEvent) {
isEvent = containsValue(statementGroup, filterClass);
}
break;
}
}
}
private boolean containsValue(StatementGroup statementGroup, Value value) {
for (Statement s : statementGroup.getStatements()) {
if (value.equals(s.getValue())) {
return true;
}
}
return false;
}
This approach worked pretty good for getting people. But the problem with events is that events like WW2 (https://www.wikidata.org/wiki/Q362) dont have the event directly mapped. The event is somewhere hidden.
Does anyone knows a way how I can easily check if the current itemDocument is an event?
You should follow the hierarchy of the subclass of of the particular instance of to a split. So starting from Q362 you will eventually reach: https://www.wikidata.org/wiki/Q350604 - armed conflict, the presumption being that WWII is everything until prior to that split, namely:
1) world war: https://www.wikidata.org/wiki/Q103495 and
2) war: https://www.wikidata.org/wiki/Q198, then
3) armed conflict: https://www.wikidata.org/wiki/Q350604 which splits to:
1) conflict: https://www.wikidata.org/wiki/Q180684, which now splits to
2) event: https://www.wikidata.org/wiki/Q1190554
And since you are only interested in events, I will do this recursively until I reach the event class.

Object-Oriented design simulating a process with states [duplicate]

I have something to do for work and I need your help.
We want to implement a FSM - Finite State Machine, to identify char sequence(like: A, B, C, A, C), and tell if it accepted.
We think to implement three classes: State, Event and Machine.
The state class presents a node in the FSM, we thought to implement it with State design pattern, every node will extend from the abstract class state and every class would handle different types of events and indicate transitions to a new state. Is it good idea in your opinion?
Second thing, we don't know how to save all the transitions. Again we thought to implement it with some kind of map, that hold the starting point and gets some kind of vector with the next states, but I'm not sure thats a good idea.
I would be happy to get some ideas of how to implement it or maybe you can give me some starting points.
How should I save the FSM, meaning how should I build the tree at the beginning of the program?
I googled it and found a lot of examples but nothing that helps me.
Thanks a lot.
The heart of a state machine is the transition table, which takes a state and a symbol (what you're calling an event) to a new state. That's just a two-index array of states. For sanity and type safety, declare the states and symbols as enumerations. I always add a "length" member in some way (language-specific) for checking array bounds. When I've hand-coded FSM's, I format the code in row and column format with whitespace fiddling. The other elements of a state machine are the initial state and the set of accepting states. The most direct implementation of the set of accepting states is an array of booleans indexed by the states. In Java, however, enumerations are classes, and you can specify an argument "accepting" in the declaration for each enumerated value and initialize it in the constructor for the enumeration.
For the machine type, you can write it as a generic class. It would take two type arguments, one for the states and one for the symbols, an array argument for the transition table, a single state for the initial. The only other detail (though it's critical) is that you have to call Enum.ordinal() to get an integer suitable for indexing the transition array, since you there's no syntax for directly declaring an array with a enumeration index (though there ought to be).
To preempt one issue, EnumMap won't work for the transition table, because the key required is a pair of enumeration values, not a single one.
enum State {
Initial( false ),
Final( true ),
Error( false );
static public final Integer length = 1 + Error.ordinal();
final boolean accepting;
State( boolean accepting ) {
this.accepting = accepting;
}
}
enum Symbol {
A, B, C;
static public final Integer length = 1 + C.ordinal();
}
State transition[][] = {
// A B C
{
State.Initial, State.Final, State.Error
}, {
State.Final, State.Initial, State.Error
}
};
EasyFSM is a dynamic Java Library which can be used to implement an FSM.
You can find documentation for the same at :
Finite State Machine in Java
Also, you can download the library at :
Java FSM Library : DynamicEasyFSM
You can implement Finite State Machine in two different ways.
Option 1:
Finite State machine with a pre-defined workflow : Recommended if you know all states in advance and state machine is almost fixed without any changes in future
Identify all possible states in your application
Identify all the events in your application
Identify all the conditions in your application, which may lead state transition
Occurrence of an event may cause transitions of state
Build a finite state machine by deciding a workflow of states & transitions.
e.g If an event 1 occurs at State 1, the state will be updated and machine state may still be in state 1.
If an event 2 occurs at State 1, on some condition evaluation, the system will move from State 1 to State 2
This design is based on State and Context patterns.
Have a look at Finite State Machine prototype classes.
Option 2:
Behavioural trees: Recommended if there are frequent changes to state machine workflow. You can dynamically add new behaviour without breaking the tree.
The base Task class provides a interface for all these tasks, the leaf tasks are the ones just mentioned, and the parent tasks are the interior nodes that decide which task to execute next.
The Tasks have only the logic they need to actually do what is required of them, all the decision logic of whether a task has started or not, if it needs to update, if it has finished with success, etc. is grouped in the TaskController class, and added by composition.
The decorators are tasks that “decorate” another class by wrapping over it and giving it additional logic.
Finally, the Blackboard class is a class owned by the parent AI that every task has a reference to. It works as a knowledge database for all the leaf tasks
Have a look at this article by Jaime Barrachina Verdia for more details
Hmm, I would suggest that you use Flyweight to implement the states. Purpose: Avoid the memory overhead of a large number of small objects. State machines can get very, very big.
http://en.wikipedia.org/wiki/Flyweight_pattern
I'm not sure that I see the need to use design pattern State to implement the nodes. The nodes in a state machine are stateless. They just match the current input symbol to the available transitions from the current state. That is, unless I have entirely forgotten how they work (which is a definite possiblilty).
If I were coding it, I would do something like this:
interface FsmNode {
public boolean canConsume(Symbol sym);
public FsmNode consume(Symbol sym);
// Other methods here to identify the state we are in
}
List<Symbol> input = getSymbols();
FsmNode current = getStartState();
for (final Symbol sym : input) {
if (!current.canConsume(sym)) {
throw new RuntimeException("FSM node " + current + " can't consume symbol " + sym);
}
current = current.consume(sym);
}
System.out.println("FSM consumed all input, end state is " + current);
What would Flyweight do in this case? Well, underneath the FsmNode there would probably be something like this:
Map<Integer, Map<Symbol, Integer>> fsm; // A state is an Integer, the transitions are from symbol to state number
FsmState makeState(int stateNum) {
return new FsmState() {
public FsmState consume(final Symbol sym) {
final Map<Symbol, Integer> transitions = fsm.get(stateNum);
if (transisions == null) {
throw new RuntimeException("Illegal state number " + stateNum);
}
final Integer nextState = transitions.get(sym); // May be null if no transition
return nextState;
}
public boolean canConsume(final Symbol sym) {
return consume(sym) != null;
}
}
}
This creates the State objects on a need-to-use basis, It allows you to use a much more efficient underlying mechanism to store the actual state machine. The one I use here (Map(Integer, Map(Symbol, Integer))) is not particulary efficient.
Note that the Wikipedia page focuses on the cases where many somewhat similar objects share the similar data, as is the case in the String implementation in Java. In my opinion, Flyweight is a tad more general, and covers any on-demand creation of objects with a short life span (use more CPU to save on a more efficient underlying data structure).
Consider the easy, lightweight Java library EasyFlow. From their docs:
With EasyFlow you can:
implement complex logic but keep your code simple and clean
handle asynchronous calls with ease and elegance
avoid concurrency by using event-driven programming approach
avoid StackOverflow error by avoiding recursion
simplify design, programming and testing of complex java applications
I design & implemented a simple finite state machine example with java.
IFiniteStateMachine: The public interface to manage the finite state machine
such as add new states to the finite state machine or transit to next states by specific actions.
interface IFiniteStateMachine {
void setStartState(IState startState);
void setEndState(IState endState);
void addState(IState startState, IState newState, Action action);
void removeState(String targetStateDesc);
IState getCurrentState();
IState getStartState();
IState getEndState();
void transit(Action action);
}
IState: The public interface to get state related info
such as state name and mappings to connected states.
interface IState {
// Returns the mapping for which one action will lead to another state
Map<String, IState> getAdjacentStates();
String getStateDesc();
void addTransit(Action action, IState nextState);
void removeTransit(String targetStateDesc);
}
Action: the class which will cause the transition of states.
public class Action {
private String mActionName;
public Action(String actionName) {
mActionName = actionName;
}
String getActionName() {
return mActionName;
}
#Override
public String toString() {
return mActionName;
}
}
StateImpl: the implementation of IState. I applied data structure such as HashMap to keep Action-State mappings.
public class StateImpl implements IState {
private HashMap<String, IState> mMapping = new HashMap<>();
private String mStateName;
public StateImpl(String stateName) {
mStateName = stateName;
}
#Override
public Map<String, IState> getAdjacentStates() {
return mMapping;
}
#Override
public String getStateDesc() {
return mStateName;
}
#Override
public void addTransit(Action action, IState state) {
mMapping.put(action.toString(), state);
}
#Override
public void removeTransit(String targetStateDesc) {
// get action which directs to target state
String targetAction = null;
for (Map.Entry<String, IState> entry : mMapping.entrySet()) {
IState state = entry.getValue();
if (state.getStateDesc().equals(targetStateDesc)) {
targetAction = entry.getKey();
}
}
mMapping.remove(targetAction);
}
}
FiniteStateMachineImpl: Implementation of IFiniteStateMachine. I use ArrayList to keep all the states.
public class FiniteStateMachineImpl implements IFiniteStateMachine {
private IState mStartState;
private IState mEndState;
private IState mCurrentState;
private ArrayList<IState> mAllStates = new ArrayList<>();
private HashMap<String, ArrayList<IState>> mMapForAllStates = new HashMap<>();
public FiniteStateMachineImpl(){}
#Override
public void setStartState(IState startState) {
mStartState = startState;
mCurrentState = startState;
mAllStates.add(startState);
// todo: might have some value
mMapForAllStates.put(startState.getStateDesc(), new ArrayList<IState>());
}
#Override
public void setEndState(IState endState) {
mEndState = endState;
mAllStates.add(endState);
mMapForAllStates.put(endState.getStateDesc(), new ArrayList<IState>());
}
#Override
public void addState(IState startState, IState newState, Action action) {
// validate startState, newState and action
// update mapping in finite state machine
mAllStates.add(newState);
final String startStateDesc = startState.getStateDesc();
final String newStateDesc = newState.getStateDesc();
mMapForAllStates.put(newStateDesc, new ArrayList<IState>());
ArrayList<IState> adjacentStateList = null;
if (mMapForAllStates.containsKey(startStateDesc)) {
adjacentStateList = mMapForAllStates.get(startStateDesc);
adjacentStateList.add(newState);
} else {
mAllStates.add(startState);
adjacentStateList = new ArrayList<>();
adjacentStateList.add(newState);
}
mMapForAllStates.put(startStateDesc, adjacentStateList);
// update mapping in startState
for (IState state : mAllStates) {
boolean isStartState = state.getStateDesc().equals(startState.getStateDesc());
if (isStartState) {
startState.addTransit(action, newState);
}
}
}
#Override
public void removeState(String targetStateDesc) {
// validate state
if (!mMapForAllStates.containsKey(targetStateDesc)) {
throw new RuntimeException("Don't have state: " + targetStateDesc);
} else {
// remove from mapping
mMapForAllStates.remove(targetStateDesc);
}
// update all state
IState targetState = null;
for (IState state : mAllStates) {
if (state.getStateDesc().equals(targetStateDesc)) {
targetState = state;
} else {
state.removeTransit(targetStateDesc);
}
}
mAllStates.remove(targetState);
}
#Override
public IState getCurrentState() {
return mCurrentState;
}
#Override
public void transit(Action action) {
if (mCurrentState == null) {
throw new RuntimeException("Please setup start state");
}
Map<String, IState> localMapping = mCurrentState.getAdjacentStates();
if (localMapping.containsKey(action.toString())) {
mCurrentState = localMapping.get(action.toString());
} else {
throw new RuntimeException("No action start from current state");
}
}
#Override
public IState getStartState() {
return mStartState;
}
#Override
public IState getEndState() {
return mEndState;
}
}
example:
public class example {
public static void main(String[] args) {
System.out.println("Finite state machine!!!");
IState startState = new StateImpl("start");
IState endState = new StateImpl("end");
IFiniteStateMachine fsm = new FiniteStateMachineImpl();
fsm.setStartState(startState);
fsm.setEndState(endState);
IState middle1 = new StateImpl("middle1");
middle1.addTransit(new Action("path1"), endState);
fsm.addState(startState, middle1, new Action("path1"));
System.out.println(fsm.getCurrentState().getStateDesc());
fsm.transit(new Action(("path1")));
System.out.println(fsm.getCurrentState().getStateDesc());
fsm.addState(middle1, endState, new Action("path1-end"));
fsm.transit(new Action(("path1-end")));
System.out.println(fsm.getCurrentState().getStateDesc());
fsm.addState(endState, middle1, new Action("path1-end"));
}
}
Full example on Github
Well this is an old question but while nobody mentioned here, I will advice to check two existing frameworks before you implement you own State Machines.
One is Spring State Machine most of you are familiar with Spring framework, which allow us to use several features of Spring like dependency injection and everything else that Spring can offer.
It is really great for modelling the lifecycle of an Apparat, with states like INITIALIZING, STARTED, ERROR, RECOVERING, SHUTTINGDOWN, etc.. but I see lots of people are trying to model a Shopping Chart, a Reservation System with it, the memory footprint a Spring State Machine is relatively big to model millions of Shopping Charts or Reservations.
One other disadvantage, Spring State Machine, while has a capability to persist itself for long running processes but it does not have any mechanism to adapt to changes in these processes, if you persist a process and you have to recover it lets say 10 days later with a change occurred in your business process because of new software release / requirement, you have no built in means to deal with it.
I have several blogs, blog1 blog2, demonstrating how you can program Spring State Machine, specially model driven way, if you want to check it.
Mainly because the disadvantages I mentioned, I advice you to look another framework first, Akka FSM (Finite State Machine) which is more fitting with its low memory footprint to have millions and millions of instances and has a capability to adapt changing long running processes.
Now you can develop with Akka framework with Java but believe me because of some missing language elements, you don't want to read the produced code, Scala is a much more fitting language to develop with Akka. Now I hear you saying Scala is too complex, I can't convince my project leads to develop with Scala, to convince you all this is an option, I developed a Proof of Concept application using a Java/Scala hybrid with all Scala Akka Finite State Machine code generated from an UML model, if you want to check it out here the links to the blogs, blog3 blog4.
I hope this information would help you.
Here is a SUPER SIMPLE implementation/example of a FSM using just "if-else"s which avoids all of the above subclassing answers (taken from Using Finite State Machines for Pattern Matching in Java, where he is looking for a string which ends with "#" followed by numbers followed by "#"--see state graph here):
public static void main(String[] args) {
String s = "A1#312#";
String digits = "0123456789";
int state = 0;
for (int ind = 0; ind < s.length(); ind++) {
if (state == 0) {
if (s.charAt(ind) == '#')
state = 1;
} else {
boolean isNumber = digits.indexOf(s.charAt(ind)) != -1;
if (state == 1) {
if (isNumber)
state = 2;
else if (s.charAt(ind) == '#')
state = 1;
else
state = 0;
} else if (state == 2) {
if (s.charAt(ind) == '#') {
state = 3;
} else if (isNumber) {
state = 2;
} else if (s.charAt(ind) == '#')
state = 1;
else
state = 0;
} else if (state == 3) {
if (s.charAt(ind) == '#')
state = 1;
else
state = 0;
}
}
} //end for loop
if (state == 3)
System.out.println("It matches");
else
System.out.println("It does not match");
}
P.S: Does not answer your question directly, but shows you how to implement a FSM very easily in Java.

Java convention in practice - return mutliple values from method

I have two questions about Java Convention. I try to make use od Robert C. Martin's "Clean Code".
Following case:
public void startProgressIfAllowed() {
try {
tryStartProgressIfAllowed();
} catch (Exception exception) {
// log error
}
}
private void tryStartProgressIfAllowed() {
if (isStartProgressAllowed()) {
stopProgressOnCurrentlyStartedTask();
startProgressOnThisTask();
}
}
private boolean isStartProgressAllowed() {
// Calls JOptionPane.showConfirmDialog with JOptionPane.YES_NO_OPTION.
// Created dialog contains checkbox indicating that saving currently started task is required.
// returns boolean depending on JOptionPane.YES_NO_OPTION clicked button
}
private void stopProgressOnCurrentlyStartedTask() {
// Saves currently started task depending on checkbox selecion property and stops currently started.
// What is the correct way to get checkbox selecion property?
}
Proposed solution:
public void tryStartProgressIfAllowed() {
if (tryToStopProgressOnStartedTaskIfNecessary()) {
startProgressOnThisTask();
}
}
private boolean tryToStopProgressOnStartedTaskIfNecessary() {
// Calls JOptionPane.showConfirmDialog with JOptionPane.YES_NO_OPTION.
// Created dialog contains checkbox indicating that saving currently started task is required.
// Depending on checkbox selecion property saves task.
// returns boolean depending on JOptionPane.YES_NO_OPTION clicked button
}
But this approach doesn't meet the "Command Query Separation" principle, because tryToStopProgressOnStartedTaskIfNecessary(...) method performs some logic and returns success/failure value.
I think this approach also doesn't meet the "One level of abstraction per function" principle, because I suppose "check" and "save" operations are on different levels of abstraction.
Is the method name correct to avoid disinformation? Maybe better name would be tryToStopProgressAndSaveStartedTaskIfNecessary(...)?
Is there any better solution for above problem?
What about the following:
public void tryStartProgressOnThisTaskIfAllowed() {
tryStopTaskInProgressIfAllowed()
if (!isTaskInProgress()) {
tryStartProgressOnThisTask();
}
}
private void tryStopTaskInProgressIfAllowed() {
if (!isTaskInProgress()) {
return;
}
TaskInProgressResult result = whatToDoWithTaskInProgress();
if (result == Result.KEEP) {
return;
} else if (result == Result.DROP)
tryDropTaskInProgress();
} else if (result == Result.SAVE) {
trySaveTaskInProgress();
}
}
About your points:
You now have two separate methods for C and Q
I think the two things whatToDoWithTaskInProgress and tryDropTaskInProgress are the same level of abstraction. If you'd inline the code of one or the other you were absolutely right of course.
I changed some of the method names according to my taste :) The only thing I still don't like is the part "OnThisTask" because this task is somewhat meaningless. Maybe it's only because the rest of the code is unknown maybe OnNextTask or OnNewTask are better.
The problem we were having is that we were thinking in UI terms YES/NO + checkbox value. But it is much better to think in business terms here. I identified three different outcomes that are of interest: KEEP, SAVE, DROP How the answer is obtained should not matter to the calling method.
This seems something to ask on CodeReview, see the drop down at the top left of the page.
An example of how such stateliness is realized in Java SE: the regex Matcher class.
String s = ...
Pattern pattern = Pattern.compile("...");
Matcher m = pattern.matcher(s);
StringBuffer sb = new StringBuffer();
while (m.find()) {
m.appendReplacement(sb, ... m.group(1) ...);
}
m.appendTail(sb);
with m.matches() and m.lookingAt as alternative circuits too.
In short state is held in a processing class on the actual data (String here).

Using OO programming to avoid multiple nested if's

I have the following code:
public void actionPerformed(ActionEvent e) {
String userInput = commandInput.getText();
if (currentLevel == 0) {
if (userInput.equals(answers.getIntroAnswers().get(0)) || userInput.equals(answers.getIntroAnswers().get(1))) {
messageDisplay.append("\n \n" + userInput + "\n");
commandInput.setText("");
messageDisplay.append("\n" + messages.getNextMessage());
currentLevel++;
getCurrentLevel();
} else {
messageDisplay.append(notValid());
}
} else if (currentLevel == 1) {
// do the same as above but with the next set of answers
}
}
What I'd like to do is somehow separate this action into it's own class and call the method /constructor within that class to do this checking else I will be stuck using nested if's and it will become very messy and hard to understand. Would I be right in thinking a method to take parameters of currentLevel and userInput in order to test the userInput against the corresponding answers based on the currentLevel? Below is a link to the rest of the classes involved:
https://github.com/addrum/TextGame.git
Would I be right in thinking a method to take parameters of currentLevel and userInput in order to test the userInput against the corresponding answers based on the currentLevel?
No. In fact, you probably want to avoid passing the current level as an explicit parameter. If you've got the level as a parameter, you will probably end up just pushing the "multiple nested ifs" into another class.
I think you need to write it like this:
InputChecker[] levelChecker = ... create an array of checker instances
....
levelChecker[currentLevel].check(userInput);
Then you need to create a class (possibly anonymous) to implement the checking for each level. Note that if you needed to you could supply the level number to a checker class via a constructor parameter and have it save it in a private instance variable.
You could expand/generalize the InputChecker interface to include other level-specific behaviour. Or indeed make this part of a Level interface.
"Is this taking the currentLevel and comparing the userInput to the current level?"
No. In my example code above it is calling a method on the InputChecker instance to do the checking. Since there are different InputChecker instances for each level, they can check different answers ... or whatever.
But if the only difference between the "input check" behaviours for each level is that they check against a different set of answers then:
levelAnswers = answers.getAnswersForLevel(currentLevel);
for (String answer : levelAnswers) {
if (userInput.equals(answer)) {
// blah blah blah
}
}
Why not create the method in the same class rather than having a different class to do that, considering other variables that method uses such as,
messageDisplay.append("\n \n" + userInput + "\n");
commandInput.setText("");
messageDisplay.append("\n" + messages.getNextMessage());
currentLevel++;
So I'd suggest creating the method in same then call it from actionPerformed
public void checks()
{
String userInput = commandInput.getText();
if (currentLevel == 0) {
if (userInput.equals(answers.getIntroAnswers().get(0)) || userInput.equals(answers.getIntroAnswers().get(1))) {
messageDisplay.append("\n \n" + userInput + "\n");
commandInput.setText("");
messageDisplay.append("\n" + messages.getNextMessage());
currentLevel++;
getCurrentLevel();
} else {
messageDisplay.append(notValid());
}
} else if (currentLevel == 1) {
// do the same as above but with the next set of answers
}
}
Then call it from actionPerformed
public void actionPerformed(ActionEvent e)
{
check():
}
So now you if's are handle in a seperate method.
To my eyes, since you are talking about levels so much, you probably should have a class that represents a level. Actually, since you obviously have more than one level, which acts slightly differently, you have two approaches.
Have a Level interface, and then make a class per level.
or
Have a Level class, with a constructor that hides the level number within the class.
After that, you can switch polymorphicly instead of nested if statements (or if's cousin, the switch statement).
Level level = currentLevel;
while (level != null) {
level.doStuff;
level = level.getNextLevel();
}

How to implement a FSM - Finite State Machine in Java

I have something to do for work and I need your help.
We want to implement a FSM - Finite State Machine, to identify char sequence(like: A, B, C, A, C), and tell if it accepted.
We think to implement three classes: State, Event and Machine.
The state class presents a node in the FSM, we thought to implement it with State design pattern, every node will extend from the abstract class state and every class would handle different types of events and indicate transitions to a new state. Is it good idea in your opinion?
Second thing, we don't know how to save all the transitions. Again we thought to implement it with some kind of map, that hold the starting point and gets some kind of vector with the next states, but I'm not sure thats a good idea.
I would be happy to get some ideas of how to implement it or maybe you can give me some starting points.
How should I save the FSM, meaning how should I build the tree at the beginning of the program?
I googled it and found a lot of examples but nothing that helps me.
Thanks a lot.
The heart of a state machine is the transition table, which takes a state and a symbol (what you're calling an event) to a new state. That's just a two-index array of states. For sanity and type safety, declare the states and symbols as enumerations. I always add a "length" member in some way (language-specific) for checking array bounds. When I've hand-coded FSM's, I format the code in row and column format with whitespace fiddling. The other elements of a state machine are the initial state and the set of accepting states. The most direct implementation of the set of accepting states is an array of booleans indexed by the states. In Java, however, enumerations are classes, and you can specify an argument "accepting" in the declaration for each enumerated value and initialize it in the constructor for the enumeration.
For the machine type, you can write it as a generic class. It would take two type arguments, one for the states and one for the symbols, an array argument for the transition table, a single state for the initial. The only other detail (though it's critical) is that you have to call Enum.ordinal() to get an integer suitable for indexing the transition array, since you there's no syntax for directly declaring an array with a enumeration index (though there ought to be).
To preempt one issue, EnumMap won't work for the transition table, because the key required is a pair of enumeration values, not a single one.
enum State {
Initial( false ),
Final( true ),
Error( false );
static public final Integer length = 1 + Error.ordinal();
final boolean accepting;
State( boolean accepting ) {
this.accepting = accepting;
}
}
enum Symbol {
A, B, C;
static public final Integer length = 1 + C.ordinal();
}
State transition[][] = {
// A B C
{
State.Initial, State.Final, State.Error
}, {
State.Final, State.Initial, State.Error
}
};
EasyFSM is a dynamic Java Library which can be used to implement an FSM.
You can find documentation for the same at :
Finite State Machine in Java
Also, you can download the library at :
Java FSM Library : DynamicEasyFSM
You can implement Finite State Machine in two different ways.
Option 1:
Finite State machine with a pre-defined workflow : Recommended if you know all states in advance and state machine is almost fixed without any changes in future
Identify all possible states in your application
Identify all the events in your application
Identify all the conditions in your application, which may lead state transition
Occurrence of an event may cause transitions of state
Build a finite state machine by deciding a workflow of states & transitions.
e.g If an event 1 occurs at State 1, the state will be updated and machine state may still be in state 1.
If an event 2 occurs at State 1, on some condition evaluation, the system will move from State 1 to State 2
This design is based on State and Context patterns.
Have a look at Finite State Machine prototype classes.
Option 2:
Behavioural trees: Recommended if there are frequent changes to state machine workflow. You can dynamically add new behaviour without breaking the tree.
The base Task class provides a interface for all these tasks, the leaf tasks are the ones just mentioned, and the parent tasks are the interior nodes that decide which task to execute next.
The Tasks have only the logic they need to actually do what is required of them, all the decision logic of whether a task has started or not, if it needs to update, if it has finished with success, etc. is grouped in the TaskController class, and added by composition.
The decorators are tasks that “decorate” another class by wrapping over it and giving it additional logic.
Finally, the Blackboard class is a class owned by the parent AI that every task has a reference to. It works as a knowledge database for all the leaf tasks
Have a look at this article by Jaime Barrachina Verdia for more details
Hmm, I would suggest that you use Flyweight to implement the states. Purpose: Avoid the memory overhead of a large number of small objects. State machines can get very, very big.
http://en.wikipedia.org/wiki/Flyweight_pattern
I'm not sure that I see the need to use design pattern State to implement the nodes. The nodes in a state machine are stateless. They just match the current input symbol to the available transitions from the current state. That is, unless I have entirely forgotten how they work (which is a definite possiblilty).
If I were coding it, I would do something like this:
interface FsmNode {
public boolean canConsume(Symbol sym);
public FsmNode consume(Symbol sym);
// Other methods here to identify the state we are in
}
List<Symbol> input = getSymbols();
FsmNode current = getStartState();
for (final Symbol sym : input) {
if (!current.canConsume(sym)) {
throw new RuntimeException("FSM node " + current + " can't consume symbol " + sym);
}
current = current.consume(sym);
}
System.out.println("FSM consumed all input, end state is " + current);
What would Flyweight do in this case? Well, underneath the FsmNode there would probably be something like this:
Map<Integer, Map<Symbol, Integer>> fsm; // A state is an Integer, the transitions are from symbol to state number
FsmState makeState(int stateNum) {
return new FsmState() {
public FsmState consume(final Symbol sym) {
final Map<Symbol, Integer> transitions = fsm.get(stateNum);
if (transisions == null) {
throw new RuntimeException("Illegal state number " + stateNum);
}
final Integer nextState = transitions.get(sym); // May be null if no transition
return nextState;
}
public boolean canConsume(final Symbol sym) {
return consume(sym) != null;
}
}
}
This creates the State objects on a need-to-use basis, It allows you to use a much more efficient underlying mechanism to store the actual state machine. The one I use here (Map(Integer, Map(Symbol, Integer))) is not particulary efficient.
Note that the Wikipedia page focuses on the cases where many somewhat similar objects share the similar data, as is the case in the String implementation in Java. In my opinion, Flyweight is a tad more general, and covers any on-demand creation of objects with a short life span (use more CPU to save on a more efficient underlying data structure).
Consider the easy, lightweight Java library EasyFlow. From their docs:
With EasyFlow you can:
implement complex logic but keep your code simple and clean
handle asynchronous calls with ease and elegance
avoid concurrency by using event-driven programming approach
avoid StackOverflow error by avoiding recursion
simplify design, programming and testing of complex java applications
I design & implemented a simple finite state machine example with java.
IFiniteStateMachine: The public interface to manage the finite state machine
such as add new states to the finite state machine or transit to next states by specific actions.
interface IFiniteStateMachine {
void setStartState(IState startState);
void setEndState(IState endState);
void addState(IState startState, IState newState, Action action);
void removeState(String targetStateDesc);
IState getCurrentState();
IState getStartState();
IState getEndState();
void transit(Action action);
}
IState: The public interface to get state related info
such as state name and mappings to connected states.
interface IState {
// Returns the mapping for which one action will lead to another state
Map<String, IState> getAdjacentStates();
String getStateDesc();
void addTransit(Action action, IState nextState);
void removeTransit(String targetStateDesc);
}
Action: the class which will cause the transition of states.
public class Action {
private String mActionName;
public Action(String actionName) {
mActionName = actionName;
}
String getActionName() {
return mActionName;
}
#Override
public String toString() {
return mActionName;
}
}
StateImpl: the implementation of IState. I applied data structure such as HashMap to keep Action-State mappings.
public class StateImpl implements IState {
private HashMap<String, IState> mMapping = new HashMap<>();
private String mStateName;
public StateImpl(String stateName) {
mStateName = stateName;
}
#Override
public Map<String, IState> getAdjacentStates() {
return mMapping;
}
#Override
public String getStateDesc() {
return mStateName;
}
#Override
public void addTransit(Action action, IState state) {
mMapping.put(action.toString(), state);
}
#Override
public void removeTransit(String targetStateDesc) {
// get action which directs to target state
String targetAction = null;
for (Map.Entry<String, IState> entry : mMapping.entrySet()) {
IState state = entry.getValue();
if (state.getStateDesc().equals(targetStateDesc)) {
targetAction = entry.getKey();
}
}
mMapping.remove(targetAction);
}
}
FiniteStateMachineImpl: Implementation of IFiniteStateMachine. I use ArrayList to keep all the states.
public class FiniteStateMachineImpl implements IFiniteStateMachine {
private IState mStartState;
private IState mEndState;
private IState mCurrentState;
private ArrayList<IState> mAllStates = new ArrayList<>();
private HashMap<String, ArrayList<IState>> mMapForAllStates = new HashMap<>();
public FiniteStateMachineImpl(){}
#Override
public void setStartState(IState startState) {
mStartState = startState;
mCurrentState = startState;
mAllStates.add(startState);
// todo: might have some value
mMapForAllStates.put(startState.getStateDesc(), new ArrayList<IState>());
}
#Override
public void setEndState(IState endState) {
mEndState = endState;
mAllStates.add(endState);
mMapForAllStates.put(endState.getStateDesc(), new ArrayList<IState>());
}
#Override
public void addState(IState startState, IState newState, Action action) {
// validate startState, newState and action
// update mapping in finite state machine
mAllStates.add(newState);
final String startStateDesc = startState.getStateDesc();
final String newStateDesc = newState.getStateDesc();
mMapForAllStates.put(newStateDesc, new ArrayList<IState>());
ArrayList<IState> adjacentStateList = null;
if (mMapForAllStates.containsKey(startStateDesc)) {
adjacentStateList = mMapForAllStates.get(startStateDesc);
adjacentStateList.add(newState);
} else {
mAllStates.add(startState);
adjacentStateList = new ArrayList<>();
adjacentStateList.add(newState);
}
mMapForAllStates.put(startStateDesc, adjacentStateList);
// update mapping in startState
for (IState state : mAllStates) {
boolean isStartState = state.getStateDesc().equals(startState.getStateDesc());
if (isStartState) {
startState.addTransit(action, newState);
}
}
}
#Override
public void removeState(String targetStateDesc) {
// validate state
if (!mMapForAllStates.containsKey(targetStateDesc)) {
throw new RuntimeException("Don't have state: " + targetStateDesc);
} else {
// remove from mapping
mMapForAllStates.remove(targetStateDesc);
}
// update all state
IState targetState = null;
for (IState state : mAllStates) {
if (state.getStateDesc().equals(targetStateDesc)) {
targetState = state;
} else {
state.removeTransit(targetStateDesc);
}
}
mAllStates.remove(targetState);
}
#Override
public IState getCurrentState() {
return mCurrentState;
}
#Override
public void transit(Action action) {
if (mCurrentState == null) {
throw new RuntimeException("Please setup start state");
}
Map<String, IState> localMapping = mCurrentState.getAdjacentStates();
if (localMapping.containsKey(action.toString())) {
mCurrentState = localMapping.get(action.toString());
} else {
throw new RuntimeException("No action start from current state");
}
}
#Override
public IState getStartState() {
return mStartState;
}
#Override
public IState getEndState() {
return mEndState;
}
}
example:
public class example {
public static void main(String[] args) {
System.out.println("Finite state machine!!!");
IState startState = new StateImpl("start");
IState endState = new StateImpl("end");
IFiniteStateMachine fsm = new FiniteStateMachineImpl();
fsm.setStartState(startState);
fsm.setEndState(endState);
IState middle1 = new StateImpl("middle1");
middle1.addTransit(new Action("path1"), endState);
fsm.addState(startState, middle1, new Action("path1"));
System.out.println(fsm.getCurrentState().getStateDesc());
fsm.transit(new Action(("path1")));
System.out.println(fsm.getCurrentState().getStateDesc());
fsm.addState(middle1, endState, new Action("path1-end"));
fsm.transit(new Action(("path1-end")));
System.out.println(fsm.getCurrentState().getStateDesc());
fsm.addState(endState, middle1, new Action("path1-end"));
}
}
Full example on Github
Well this is an old question but while nobody mentioned here, I will advice to check two existing frameworks before you implement you own State Machines.
One is Spring State Machine most of you are familiar with Spring framework, which allow us to use several features of Spring like dependency injection and everything else that Spring can offer.
It is really great for modelling the lifecycle of an Apparat, with states like INITIALIZING, STARTED, ERROR, RECOVERING, SHUTTINGDOWN, etc.. but I see lots of people are trying to model a Shopping Chart, a Reservation System with it, the memory footprint a Spring State Machine is relatively big to model millions of Shopping Charts or Reservations.
One other disadvantage, Spring State Machine, while has a capability to persist itself for long running processes but it does not have any mechanism to adapt to changes in these processes, if you persist a process and you have to recover it lets say 10 days later with a change occurred in your business process because of new software release / requirement, you have no built in means to deal with it.
I have several blogs, blog1 blog2, demonstrating how you can program Spring State Machine, specially model driven way, if you want to check it.
Mainly because the disadvantages I mentioned, I advice you to look another framework first, Akka FSM (Finite State Machine) which is more fitting with its low memory footprint to have millions and millions of instances and has a capability to adapt changing long running processes.
Now you can develop with Akka framework with Java but believe me because of some missing language elements, you don't want to read the produced code, Scala is a much more fitting language to develop with Akka. Now I hear you saying Scala is too complex, I can't convince my project leads to develop with Scala, to convince you all this is an option, I developed a Proof of Concept application using a Java/Scala hybrid with all Scala Akka Finite State Machine code generated from an UML model, if you want to check it out here the links to the blogs, blog3 blog4.
I hope this information would help you.
Here is a SUPER SIMPLE implementation/example of a FSM using just "if-else"s which avoids all of the above subclassing answers (taken from Using Finite State Machines for Pattern Matching in Java, where he is looking for a string which ends with "#" followed by numbers followed by "#"--see state graph here):
public static void main(String[] args) {
String s = "A1#312#";
String digits = "0123456789";
int state = 0;
for (int ind = 0; ind < s.length(); ind++) {
if (state == 0) {
if (s.charAt(ind) == '#')
state = 1;
} else {
boolean isNumber = digits.indexOf(s.charAt(ind)) != -1;
if (state == 1) {
if (isNumber)
state = 2;
else if (s.charAt(ind) == '#')
state = 1;
else
state = 0;
} else if (state == 2) {
if (s.charAt(ind) == '#') {
state = 3;
} else if (isNumber) {
state = 2;
} else if (s.charAt(ind) == '#')
state = 1;
else
state = 0;
} else if (state == 3) {
if (s.charAt(ind) == '#')
state = 1;
else
state = 0;
}
}
} //end for loop
if (state == 3)
System.out.println("It matches");
else
System.out.println("It does not match");
}
P.S: Does not answer your question directly, but shows you how to implement a FSM very easily in Java.

Categories

Resources