Introducing the Interpreter design pattern

Introducing the Interpreter design pattern

Read Time : 4 Minutes

Thursday, 20 April 2023

Design patterns are proven solutions to software design problems. They help improve code quality, promote reusability, and increase maintainability. We use them to save time and produce quality, extensible and flexible code. In this article, we are going to introduce the Interpreter design pattern.

The Interpreter design pattern is a behavioral design pattern that provides a way to interpret sentences or phrases in a defined language. If certain sentences and phrases are used somewhere in the program and you need a solution to analyze, understand and calculate those sentences and phrases, the Interpreter design pattern will be a useful algorithm.

 

This template consists of the following components:

  • Abstract Expression: Defines an interface or abstract class for all expressions in the language. This interface usually has an interpret method that is implemented in all kinds of main expressions.
  • Terminal Expression: It is an implementation of the AbstractExpression interface. This implementation represents a core element in the defined language. That is, this expression cannot be divided into smaller parts. Like the variables in an expression.
  • Non-terminal Expression: This is also a specific implementation of the AbstractExpression interface. It represents a compound element in the language, such as an expression consisting of several variables and operators.
  • Client: It is an entity that creates the input statement and sends it to the interpreter for evaluation.

The Interpreter pattern can be used to define a language for a specific domain and provides a way to evaluate sentences or expressions in that language. It is useful when you need to parse and interpret data structures or complex expressions, such as in compilers or query languages.

Examples of this pattern in real-world applications include SQL query interpreters, regular expression matchers, and programming language interpreters. In the following, we will understand this pattern better with a simple example.

Suppose we want to make a simple calculator that can perform the four basic operations of addition, subtraction, multiplication and division. We can use the Interpreter pattern to display these expressions and evaluate them.

First, we define the abstract expression interface:

public interface IExpression
{
    int Interpret();
}

In the next step, we define an expression from the group of basic expressions that include expressions that cannot be divided into smaller parts to represent numbers:

public class NumberExpression : IExpression
{
    private readonly int _number;
    public NumberExpression(int number)
    {
        _number = number;
    }
    public int Interpret()
    {
        return _number;
    }
}

You can see that this expression, being the basic reason, does not need any special operation to interpret and just returns the value. Then, we define the four main expressions for addition, subtraction, multiplication and division operations:

public class AddExpression : IExpression
{
   private readonly Expression _leftExpression;
   private readonly Expression _rightExpression;
   public AddExpression(Expression leftExpression, Expression rightExpression)
   {
       _leftExpression = leftExpression;
        _rightExpression = rightExpression;
   }
   public override int Interpret()
   {
       var leftOperand = _leftExpression.Interpret();
        var rightOperand = _rightExpression.Interpret();
        return leftOperand + rightOperand;
   }
}
public class SubtractExpression : Expression
{
//Similar to AddExpression Class
}
public class MultiplicationExpression : Expression
{
//Similar to AddExpression Class
}
public class DivisionExpression : Expression
{
//Similar to AddExpression Class
}

Finally, we define the usage code that creates and executes the expressions:

public static void Main()
{
// Create the expression tree: ((3 + (4 * 5)) - (6 / 2))
                var expression = new SubtractExpression(
                                new AddExpression(
                                                new NumberExpression(3),
                                                new MultiplicationExpression(
                                                                new NumberExpression(4),
                                                                new NumberExpression(5))),
                                new DivisionExpression(
                                                new NumberExpression(6),
                                                new NumberExpression(2)));
                // Evaluate the expression
                var result = expression.Interpret();
                Console.WriteLine($"Result: {result}");
}

In this example, we first create an expression that expresses the expression 3+4*5-6/2 and calculate it using the Interpret method. Note that this is a simple example. The Interpreter pattern can be used to define much more complex languages and expressions.

To read about other design patterns, you can use the list below. There is also a code repository on GitHub that includes all the design patterns.

design patterns

Creational:Factory Design Pattern
Builder Design Pattern
Singleton Design Pattern
Prototype Design Pattern
Abstract Factory Design Pattern
Structural:Adapter Design Pattern
Bridge Design Pattern
Composite Design Pattern
Decorator Design Pattern
Facade Design Pattern
Flyweight Design Pattern
Proxy Design Pattern
Behavioral:Chain of Responsibility Design Pattern
Command Design Pattern
Interpreter Design Pattern
Mediator Design Pattern
Memento Design Pattern
Observer Design Pattern
State Design Pattern
Strategy Design Pattern
Template Method Design Pattern
Visitor Design Pattern
Iterator Design Pattern
  • Share:
reza babakhani
Reza Babakhani

I am Reza Babakhani, a software developer. Here I write my experiences, opinions and suggestions about technology. I hope that what I write is useful for you.

Latest post

Service Mesh Simplifying Microservice Communication

In the ever-evolving landscape of software development, microservices architecture has gained considerable popularity due to its scalability, flexibility, and extensibility. However, as the number of microservices in an application increases, it becomes increasingly challenging to manage their communication and ensure that they are all properly visible. This is where Service Mesh comes into play.

The Importance of Edge Computing

Due to the speed of technological evolution, one of the concepts that has attracted a lot of attention and changes the way we interact with digital systems is edge computing.

What is event-driven architecture?

Event-driven architecture (EDA) is a software design pattern that has become increasingly popular in modern software development. In this architecture, the flow of data is determined by the occurrence of events. Unlike traditional centralized systems that are constantly checking for new status. Event-driven architecture is especially useful for systems that need to process large amounts of data in real-time.

Comments

commented user
Tobias Tuesday, 11 June 2024

Where is the 'Expression' class declared, that the non-terminal expressions inherit from?

reza babakhani
Reza Babakhani Thursday, 02 January 2025

Sorry for the mistake. It was a typo and has been corrected. Thank you.

leave a comment