Interpreter Design Pattern in C# with Example

1. Definition

The Interpreter Design Pattern provides a way to evaluate language grammar or expressions for particular languages. It primarily involves representing each rule of grammar as a separate class.

2. Problem Statement

Consider a scenario where you have a simple language that calculates arithmetic operations for numbers (like adding and subtracting). Parsing and evaluating such strings as "5 + 3" or "10 - 4" can become a challenge, especially as the language grows in complexity.

3. Solution

The Interpreter pattern suggests modeling the domain with a set of classes representing grammar rules. By doing this, you can interpret (or evaluate) sentences (or expressions) of the language using a structured representation that corresponds to the grammar of the language.

4. Real-World Use Cases

1. Query language interpreters like SQL.

2. Simple scripting languages.

3. Text-processing tools and compilers.

5. Implementation Steps

1. Define an abstract expression that declares an interpret operation.

2. For every rule in the grammar, define a concrete expression.

3. The client creates sentences in the language using the grammar and interprets them.

6. Implementation in C#

// Step 1: The Abstract Expression
public interface IExpression
{
    int Interpret();
}

// Step 2: Concrete Expressions
public class Number : IExpression
{
    private int _number;

    public Number(int number)
    {
        _number = number;
    }

    public int Interpret()
    {
        return _number;
    }
}

public class Add : IExpression
{
    private IExpression _leftExpression;
    private IExpression _rightExpression;

    public Add(IExpression left, IExpression right)
    {
        _leftExpression = left;
        _rightExpression = right;
    }

    public int Interpret()
    {
        return _leftExpression.Interpret() + _rightExpression.Interpret();
    }
}

public class Subtract : IExpression
{
    private IExpression _leftExpression;
    private IExpression _rightExpression;

    public Subtract(IExpression left, IExpression right)
    {
        _leftExpression = left;
        _rightExpression = right;
    }

    public int Interpret()
    {
        return _leftExpression.Interpret() - _rightExpression.Interpret();
    }
}

public class Program
{
    public static void Main()
    {
        // Client code
        IExpression left = new Number(5);
        IExpression right = new Number(3);
        IExpression add = new Add(left, right);

        Console.WriteLine($"Result of expression (5 + 3): {add.Interpret()}");
    }
}

Output:

Result of expression (5 + 3): 8

Explanation:

Each rule of our arithmetic grammar (addition and subtraction) is represented by a class. The Number class represents a number in our language. The Add and Subtract classes represent addition and subtraction operations, respectively. When the Interpret method is called on an expression, it evaluates the expression based on the rules defined in these classes.

7. When to use?

1. Use the Interpreter pattern when you have a simple language to interpret, and the grammar is not so complex.

2. When the grammar is hierarchical and can be represented with an abstract syntax tree.

3. Avoid the pattern for complex grammars as it can become large and unmanageable.


Comments