05 Dec 2023
Advanced
The Interpreter design pattern is a behavioral pattern that defines a grammar for interpreting language expressions and provides an interpreter to interpret sentences in that language. In C#, the Interpreter pattern typically involves the following main components:
-
Abstract Expression:
- Declares an interface for interpreting an expression.
- Usually, this interface includes an
Interpretmethod.
public interface IExpression { bool Interpret(string context); } -
Terminal Expression:
- Implements the
IExpressioninterface. - Represents a terminal symbol in the grammar (i.e., an atomic element that cannot be further divided).
public class TerminalExpression : IExpression { private string terminal; public TerminalExpression(string terminal) { this.terminal = terminal; } public bool Interpret(string context) { return context.Contains(terminal); } } - Implements the
-
Non-terminal Expression:
- Also implements the
IExpressioninterface. - Represents a non-terminal symbol in the grammar, usually consisting of multiple terminal and/or non-terminal expressions.
public class AndExpression : IExpression { private IExpression expression1; private IExpression expression2; public AndExpression(IExpression expression1, IExpression expression2) { this.expression1 = expression1; this.expression2 = expression2; } public bool Interpret(string context) { return expression1.Interpret(context) && expression2.Interpret(context); } }public class OrExpression : IExpression { private IExpression expression1; private IExpression expression2; public OrExpression(IExpression expression1, IExpression expression2) { this.expression1 = expression1; this.expression2 = expression2; } public bool Interpret(string context) { return expression1.Interpret(context) || expression2.Interpret(context); } } - Also implements the
-
Context:
- Contains information that needs to be interpreted.
- Often not explicitly used in the basic Interpreter pattern but may be passed to the
Interpretmethod.
public class Context { private string input; public Context(string input) { this.input = input; } public string Input { get { return input; } } } -
Client:
- Builds the abstract syntax tree of expressions.
- Provides the context and invokes the
Interpretmethod to interpret the expression.
class Client { static void Main() { IExpression expression1 = new TerminalExpression("hello"); IExpression expression2 = new TerminalExpression("world"); IExpression andExpression = new AndExpression(expression1, expression2); IExpression expression3 = new TerminalExpression("foo"); IExpression expression4 = new TerminalExpression("bar"); IExpression orExpression = new OrExpression(expression3, expression4); Context context = new Context("hello world"); bool result1 = andExpression.Interpret(context.Input); bool result2 = orExpression.Interpret(context.Input); Console.WriteLine($"AND expression result: {result1}"); Console.WriteLine($"OR expression result: {result2}"); } }
In this example:
IExpressionis the abstract expression interface that declares theInterpretmethod.TerminalExpressionis a concrete terminal expression class that interprets a single symbol or atomic element.AndExpressionandOrExpressionare concrete non-terminal expression classes that interpret combinations of expressions.Contextis an optional class that contains the information to be interpreted.- The
Clientbuilds the abstract syntax tree of expressions, provides the context, and invokes theInterpretmethod to interpret the expression.
The Interpreter pattern is useful when you have a grammar for a language, and you want to build an interpreter to interpret sentences in that language. It allows you to define the grammar using a set of classes representing expressions and provides a way to evaluate those expressions.