Skip to main content

Command Palette

Search for a command to run...

Interpreter - Design Pattern

Software Architecture Simplified

Updated
3 min readView as Markdown
Interpreter - Design Pattern
V

I am a software engineer with over 10 years of experience in a huge variety of projects and architectures, some simple others considerably complex.

Some of my main skills include Software Architecture, Web Development, ASP.NET Core, React.js, Entity Framework Core, Javascript, SQL and Web Services.

I consider myself passionate about coding as I really fell excited about learning technologies and using them to automate and improve processes.

Objective 🎯

Provide a way to interpret/evaluate a language grammar or expression.

Type

✔️Behavioral: Describes how objects interact/communicate between themselves.

Creational: Describes how to instantiate an object without large and complex.

Structural: Describes how objects/classes are composed to form larger structures.

UML 📐

image.png

Participants 🔗

• AbstractExpression:

  • Declares an Evaluate() operation that all nodes (leaf and non-leaf) must override

• Terminal Expression:

  • Implements a concrete operation

• Nonterminal Expression:

  • Implements an operation and execute the next expression

• Interpreter:

  • Defines an interface to receive the Context
  • Based on the Context (user’s input) will create the Expression classes
  • Will interpret the user’s input (Context) by executing the Evaluate method of the Expression classes

• Client:

  • Will receive the user’s input data
  • Responsible to create and maintain the Context
  • Will instantiate an Interpreter object and call the method Interpret passing the Context as argument

Notes 📝

• This pattern is recommended for relatively simple grammar interpretation, which doesn't need to evolve and extend much.

• Terminal Expressions are considered the leaf nodes

• Non-Terminal Expressions are considered the non-leaf nodes

image.png

• The example below illustrates how this pattern can be used to interpret SQL statements

image.png

Sample Code 🎮

Structural Example 🏛️

image.png

public static class InterpreterStructural
    {
        // Client
        public static void Execute()
        {
            Context lContext = new Context();
            lContext._UserInput = "AABBCC";

            Interpreter lInterpreter = new Interpreter();
            lInterpreter.Interprete(lContext);
        }
    }

    public class Interpreter
    {
        public void Interprete(Context prContext)
        {
            List<Expression> _Expressions = new List<Expression>();
            _Expressions.Add(new NonTerminalExpression());
            _Expressions.Add(new TerminalExpression());

            foreach (Expression lExpressionCurrent in _Expressions)
            {
                lExpressionCurrent.Evaluate(prContext);
            }
        }
    }

    public abstract class Expression
    {
        public abstract void Evaluate(Context prContext);
    }

    public class NonTerminalExpression : Expression
    {
        public override void Evaluate(Context prContext)
        {
            Console.WriteLine($"--Executing a Non-Terminal Operation with the input \"{prContext._UserInput}\"");
        }
    }

    public class TerminalExpression : Expression
    {
        public override void Evaluate(Context prContext)
        {
            Console.WriteLine($"----Executing a Terminal Operation with the input \"{prContext._UserInput}\"");
        }
    }

    public class Context
    {
        public string _UserInput { get; set; }
    }

Output

image.png

Real-world Example 🔥

image.png

public static class InterpreterPractical
    {
        // Client
        public static void Execute()
        {
            CommandLineContext lCommandLineContext = new CommandLineContext();
            lCommandLineContext._UserExpression = " Lorem Ipsum Dolor Sit Amet, Consectetur -u -t";

            CommandLineInterpreter lCommandLineInterpreter = new CommandLineInterpreter();
            lCommandLineInterpreter.Interprete(lCommandLineContext);

            lCommandLineContext._UserExpression = " Lorem Ipsum Dolor Sit Amet, Consectetur -l";
            lCommandLineInterpreter.Interprete(lCommandLineContext);
        }
    }

    public class CommandLineInterpreter
    {
        public void Interprete(CommandLineContext prCommandLineContext)
        {
            List<CommandLineExpression> _CommandLineExpressions = new List<CommandLineExpression>();

            // GET EXPRESSIONS
            List<string> lExpressions = prCommandLineContext._UserExpression.Substring(prCommandLineContext._UserExpression.IndexOf("-")).Split(" ").ToList();

            prCommandLineContext._Result = prCommandLineContext._UserExpression.Substring(0, prCommandLineContext._UserExpression.IndexOf("-"));

            foreach (string lExpressionCUrrent in lExpressions)
            {
                switch (lExpressionCUrrent)
                {
                    case ("-u"): _CommandLineExpressions.Add(new ToUpperCaseExpression()); break;
                    case ("-l"): _CommandLineExpressions.Add(new ToLowerCaseExpression()); break;
                    case ("-t"): _CommandLineExpressions.Add(new TrimExpression()); break;
                    default: break;
                }
            }

            // EXECUTE EXPRESSIONS
            Console.WriteLine($"\n\r- INTERPRETING INPUT: \"{prCommandLineContext._Result}\"");
            foreach (CommandLineExpression lCommandLineExpressionCurrent in _CommandLineExpressions)
            {
                lCommandLineExpressionCurrent.Evaluate(prCommandLineContext);
                Console.WriteLine($"-- {lCommandLineExpressionCurrent.GetType().Name} Executed - Result: \"{prCommandLineContext._Result}\"");
            }
            Console.WriteLine($"- INTERPRETATION RESULT: \"{prCommandLineContext._Result}\"");
        }
    }

    public abstract class CommandLineExpression
    {
        public abstract void Evaluate(CommandLineContext prCommandLineContext);
    }

    public class ToUpperCaseExpression : CommandLineExpression
    {
        public override void Evaluate(CommandLineContext prCommandLineContext)
        {
            prCommandLineContext._Result = prCommandLineContext._Result.ToUpper();
        }
    }

    public class ToLowerCaseExpression : CommandLineExpression
    {
        public override void Evaluate(CommandLineContext prCommandLineContext)
        {
            prCommandLineContext._Result = prCommandLineContext._Result.ToLower();
        }
    }

    public class TrimExpression : CommandLineExpression
    {
        public override void Evaluate(CommandLineContext prCommandLineContext)
        {
            prCommandLineContext._Result = prCommandLineContext._Result.Trim();
        }
    }

    public class CommandLineContext
    {
        public string _UserExpression { get; set; }
        public string _Result { get; set; }
    }

Output

image.png

Source Code 🎲

https://github.com/VictorLins/DesignPatterns