Interpreter pattern provides a way to evaluate language grammar or expression. The term interpreter means a person who interprets the stuff in a foreign language into a language that is understandable. In the terms of computer programming, an interpreter is a pattern in which the programming language is evaluated line by line. This type of pattern comes under behavioral pattern of the 23 GoF Design Patterns.
Interpreter pattern
According to the Gang of Four:
Given a language, define a representation for its grammar along with an interpreter that uses the representation to interpret sentences in the language.
Spring 5 Design Pattern Book
Behavioral pattern is a design pattern through which common communication patterns are identified between different objects. This way the communication is carried out in more flexible way. The areas of use of this design pattern of the interpreter are symbol processing engine, SQL parsing etc.
also read:
UML class diagram for Interpreter Design Pattern
There is a following UML diagram illustrates about this patterns and its components.
Benefits of Interpreter Pattern
The following lists the benefits of using the Interpreter pattern:
- This pattern allows you to change and extend the grammar easily.
- Using the expression language is very easy
Steps to Implementation for this Pattern
Here are the following steps for the implementation of the interpreter.
Step 1: AbstractExpression (Expression)
The first step for the implementation of the interpreter is the creation of the expression interface “Expression.java”.
/** * */ package com.doj.patterns.behavior.interpreter; /** * @author Dinesh.Rajput * */ public abstract class Expression { public void Interpret(Context context){ if (context.get_input().length() == 0) return; if (context.get_input().startsWith(nine())) { context.set_output(context.get_output()+ 9 * multiplier()); context.set_input(context.get_input().substring(2)); }else if (context.get_input().startsWith(four())){ context.set_output(context.get_output()+ 4 * multiplier()); context.set_input(context.get_input().substring(2)); }else if (context.get_input().startsWith(five())){ context.set_output(context.get_output()+ 5 * multiplier()); context.set_input(context.get_input().substring(1)); } while (context.get_input().startsWith(one())){ context.set_output(context.get_output()+ 1 * multiplier()); context.set_input(context.get_input().substring(1)); } } public abstract String one(); public abstract String four(); public abstract String five(); public abstract String nine(); public abstract int multiplier(); }
Step 2: TerminalExpression ( ThousandExpression, HundredExpression, TenExpression, OneExpression )
After the creation of the interface or abstract, the second step is to use the created interface to create concrete classes.
ThousandExpression.java
/** * */ package com.doj.patterns.behavior.interpreter; /** * @author Dinesh.Rajput * */ public class ThousandExpression extends Expression { @Override public String one() { return "M"; } @Override public String four() { return " "; } @Override public String five() { return " "; } @Override public String nine() { return " "; } @Override public int multiplier() { return 1000; } }
HundredExpression.java
/** * */ package com.doj.patterns.behavior.interpreter; /** * @author Dinesh.Rajput * */ public class HundredExpression extends Expression { @Override public String one() { return "C"; } @Override public String four() { return "CD"; } @Override public String five() { return "D"; } @Override public String nine() { return "CM"; } @Override public int multiplier() { return 100; } }
TenExpression.java
/** * */ package com.doj.patterns.behavior.interpreter; /** * @author Dinesh.Rajput * */ public class TenExpression extends Expression { @Override public String one() { return "X"; } @Override public String four() { return "XL"; } @Override public String five() { return "L"; } @Override public String nine() { return "XC"; } @Override public int multiplier() { return 10; } }
OneExpression.java
/** * */ package com.doj.patterns.behavior.interpreter; /** * @author Dinesh.Rajput * */ public class OneExpression extends Expression { @Override public String one() { return "I"; } @Override public String four() { return "IV"; } @Override public String five() { return "V"; } @Override public String nine() { return "IX"; } @Override public int multiplier() { return 1; } }
Step 3: Context (Context.java)
It contains information that is global to the interpreter
/** * */ package com.doj.patterns.behavior.interpreter; /** * @author Dinesh.Rajput * */ public class Context { private String _input; private int _output; public Context(String _input) { super(); this._input = _input; } public String get_input() { return _input; } public void set_input(String _input) { this._input = _input; } public int get_output() { return _output; } public void set_output(int _output) { this._output = _output; } }
Step 4: Let’s create Interpreterpatterndemo.java file using the expression class to create rules and then parse them.
/** * */ package com.doj.patterns.behavior.interpreter; import java.util.ArrayList; import java.util.List; /** * @author Dinesh.Rajput * */ public class InterpreterPatternDemo { /** * @param args */ public static void main(String[] args) { String roman = "MMCDXXVIIVI"; Context context = new Context(roman); // Build the 'parse tree' List tree = new ArrayList<>(); tree.add(new ThousandExpression()); tree.add(new HundredExpression()); tree.add(new TenExpression()); tree.add(new OneExpression()); // Interpret for (Expression exp : tree){ exp.Interpret(context); } System.out.println(roman+" = "+context.get_output()); } }
Step 5: The fifth and the final step is to verify the output.
MMCDXXVIIVI = 2427