The Interpreter pattern is a behavioral design pattern that is used to define a language or grammar for a problem domain and provides a way to evaluate or interpret sentences in that language. It allows you to build an interpreter that can parse sentences in the defined language and perform actions based on the parsed expressions.
interface Vehicle {
void drive();
void stop();
void refuel();
}
// Context
class Car implements Vehicle {
private String plateNumber;
public Car(String plateNumber) {
this.plateNumber = plateNumber;
}
@Override
public void drive() {
System.out.println("The car " + plateNumber + " is driving.");
}
@Override
public void stop() {
System.out.println("The car " + plateNumber + " has stopped.");
}
@Override
public void refuel() {
System.out.println("The car " + plateNumber + " is being refueled.");
}
}
// Context
class Truck implements Vehicle {
private String plateNumber;
public Truck(String plateNumber) {
this.plateNumber = plateNumber;
}
@Override
public void drive() {
System.out.println("The truck " + plateNumber + " is driving.");
}
@Override
public void stop() {
System.out.println("The truck" + plateNumber + " has stopped.");
}
@Override
public void refuel() {
System.out.println("The truck " + plateNumber + " is being refueled.");
}
}
// Abstract Expression Interface
interface Expression {
void interpret(Vehicle vehicle);
}
// Terminal Expresion
class DriveExpression implements Expression {
@Override
public void interpret(Vehicle vehicle) {
vehicle.drive();
}
}
// Terminal Expresion
class StopExpression implements Expression {
@Override
public void interpret(Vehicle vehicle) {
vehicle.stop();
}
}
// Terminal Expresion
class RefuelExpression implements Expression {
@Override
public void interpret(Vehicle vehicle) {
vehicle.refuel();
}
}
// Non-Terminal Expresion
class CompositeExpression implements Expression {
private List<Expression> expressions;
public CompositeExpression() {
expressions = new ArrayList<>();
}
public void addExpression(Expression expression) {
expressions.add(expression);
}
@Override
public void interpret(Vehicle vehicle) {
for (Expression expression : expressions) {
expression.interpret(vehicle);
}
}
}
class CommandParser {
private final Map<String, Expression> expressions;
public CommandParser() {
expressions = new HashMap<>();
expressions.put("drive", new DriveExpression());
expressions.put("stop", new StopExpression());
expressions.put("refuel", new RefuelExpression());
}
public void parse(String command, Vehicle vehicle) {
Expression expression = expressions.get(command);
if (expression != null) {
expression.interpret(vehicle);
} else {
System.out.println("Invalid command: " + command);
}
}
}
public class Main {
public static void main(String[] args) {
Vehicle car = new Car("ABC123");
StopExpression stop = new StopExpression();
RefuelExpression refuel = new RefuelExpression();
stop.interpret(car); // Output: The car ABC123 has stopped.
refuel.interpret(car); // Output: The car ABC123 is being refueled.
// Interpret commands using the parser
CommandParser parser = new CommandParser();
parser.parse("drive", car); // Output: The car ABC123 is driving.
parser.parse("stop", car); // Output: The car ABC123 has stopped.
parser.parse("refuel_stop", car); // Output: Invalid command: refuel_stop
parser.parse("park", car); // Output: Invalid command: park
// Create a composite expression for refueling and stopping
CompositeExpression compositeExpression = new CompositeExpression();
compositeExpression.addExpression(new StopExpression());
compositeExpression.addExpression(new RefuelExpression());
compositeExpression.interpret(car); // Output: The car ABC123 has stopped. The car ABC123 is being refueled.
}
}
In this example, say we want to define a simple language for specifying actions or commands related to vehicles. We might have commands like "drive", "stop", "refuel", etc. Each command can be associated with a specific action that should be performed on a vehicle.
Certainly! The Interpreter pattern is a behavioral design pattern that is used to define a language or grammar for a problem domain and provides a way to evaluate or interpret sentences in that language. It allows you to build an interpreter that can parse sentences in the defined language and perform actions based on the parsed expressions.
In the context of the Vehicle
example, let's say we want to define a simple language for specifying actions or commands related to vehicles. For example, we might have commands like "drive", "stop", "refuel", etc. Each command can be associated with a specific action that should be performed on a vehicle.
We'll need the following components to implement the interpreter pattern:
-
Abstract Expression (
Expression
): This interface represents the abstract syntax tree node of the language. It declares aninterpret
method that takes aVehicle
object and performs the specific action associated with the expression. -
Terminal Expression (
TerminalExpression
): This class implements theExpression
interface and represents the terminal expressions or leaf nodes of the abstract syntax tree. In our example, we can have classes likeDriveExpression
,StopExpression
,RefuelExpression
, etc., which implement theinterpret
method accordingly. -
Non-terminal Expression (
NonTerminalExpression
): This class (CompositeExpression
) also implements theExpression
interface and represents the non-terminal expressions or composite nodes of the abstract syntax tree. It can contain multiple child expressions and implement theinterpret
method by performing some composite operation.
We define the Expression
interface that declares the interpret
method. Each concrete expression class (DriveExpression
, StopExpression
, RefuelExpression
) implements the interpret
method to perform the specific action on the Vehicle
object. The CommandParser
class acts as the interpreter and contains a mapping of commands to corresponding expressions. It parses the input command and invokes the interpret
method on the corresponding expression. If the command is not recognized, it displays an error message.
Use the Interpreter pattern when you need to interpret and evaluate expressions or grammars in your application (SQL,Regex ...)
- It's best to design apply this pattern when you have a language or a domain-specific problem that can be represented as an Abstract Syntax Tree (AST)
- Or when you want to create a domain-specific language (DSL) or provide a way to specify complex rules or behaviors using a simple syntax.
Use the Interpreter pattern when you want to decouple the grammar and rules from the implementation details of the expressions.
Use the Interpreter pattern when the grammar is simple and stable, but you expect frequent variations or extensions in the expressions.
The usage of the Interpreter pattern can be extremely rare. However, it is commonly seen used in areas such as query languages, regular expressions, mathematical expressions, template engines, and rule-based systems. It allows you to define a language, grammar, or set of rules and provide a way to interpret and process them efficiently.