Using ENUM and a map could be a neat way to remove conditional logic, like switch cases in our code.
Another approach could be to use State design pattern, but if you don’t want to create many classes and your use case is pretty simple and using ENUM will not involve repetition of logic. Then using this approach might not be a bad option.
Let see an example :
suppose we have the class to evaluate Infix Expressions with switch cases :
public class Expression { private char op; private Expression left; private Expression right; private int constant; public Expression(int constant) { this.op = 'c'; this.constant = constant; } public Expression(char op, Expression left, Expression right) { this.op = op; this.left = left; this.right = right; } public int evaluate() { switch (op) { case 'c': return constant; case '+': return left.evaluate() + right.evaluate(); case '-': return left.evaluate() - right.evaluate(); case '*': return left.evaluate() * right.evaluate(); case '/': return left.evaluate() / right.evaluate(); default: throw new IllegalStateException(); } } public String getExpressionDescription() { switch (op) { case 'c': return "Constant"; case '+': return "Addition"; case '-': return "Subtraction"; case '*': return "Multiplication"; case '/': return "Division"; default: throw new IllegalStateException(); } } }
We will make an ENUM class of type ExpressionType and use a map in order to remove switch case logic.
We will override the methods ‘toString’ and ‘evaluate’ for each ENUM type.
In order to get rid of multiple switch cases conditions, we will store the mapping of each ‘operand’ with the corresponding ExpressionType in a map.
The map would get initialised in a static block in the same class and hence we will hide it from the class using it.
public enum ExpressionType { ADD { @Override public String toString() { return "ADDITION"; } @Override public int evaluate(int left, int right) { return left + right; } }, SUBTRACT { @Override public String toString() { return "SUBTRACTION"; } @Override public int evaluate(int left, int right) { return left - right; } }, MULTIPLY { @Override public String toString() { return "MULTIPLICATION"; } @Override public int evaluate(int left, int right) { return left * right; } }, DIVIDE { @Override public String toString() { return "DIVISION"; } @Override public int evaluate(int left, int right) { return left / right; } }; private static Map<String, ExpressionType> expressionMap = new HashMap<String, ExpressionType>(); static { expressionMap.put(Character.toString('+'), ADD); expressionMap.put(Character.toString('-'), SUBTRACT); expressionMap.put(Character.toString('*'), MULTIPLY); expressionMap.put(Character.toString('/'), DIVIDE); } public abstract String toString(); public abstract int evaluate(int left, int right); public static ExpressionType get(char c) { return expressionMap.get(Character.toString(c)); } }
Hence the class Expression becomes :
public class Expression { private char op; private Expression left; private Expression right; private int constant; public Expression(int constant) { this.op = 'c'; this.constant = constant; } public Expression(char op, Expression left, Expression right) { this.op = op; this.left = left; this.right = right; } public int evaluate() { if (op == 'c') { return constant; } else if (ExpressionType.get(op) != null) { return ExpressionType.get(op).evaluate(left.evaluate(), right.evaluate()); } else { throw new IllegalStateException(); } } public String getExpressionDescription() { if (op == 'c') { return "Constant"; } else if (ExpressionType.get(op) != null) { return ExpressionType.get(op).toString(); } else { throw new IllegalStateException(); } } }
This simple approach looks quite neat and provides good readability of code.
