Design Patterns: Interpreter

The Interpreter Design Pattern was created to solve an issue interpreting data from a context. By having separate classes, one for each type of interpretation, it is possible to have well-defined classes with single purposes.

To do this design our application needs a structure similar to the following:

  1. Context <-- Client --> Expression1   
  2. `-> Expression2   
The client has a context that is sent to a list of expression interpreters and they set the output to the final result.

For example, we can have expressions to parse decimal numbers into roman numerals.
  1. public class RomanContext    
  2. {    
  3.     public RomanContext(int input)    
  4.     {    
  5.         Input = input;    
  6.     }    
  7.      
  8.     public int Input { getset; }    
  9.      
  10.     public string Output { getset; }    
  11. }    
  12.      
  13. public abstract class Expression    
  14. {    
  15.     public abstract void Interpret(RomanContext value);    
  16. }    
  17.      
  18. public class RomanOneExpression : Expression    
  19. {    
  20.     public override void Interpret(RomanContext value)    
  21.     {    
  22.         while ((value.Input - 9) >= 0)    
  23.         {    
  24.             value.Output += "IX";    
  25.      
  26.             value.Input -= 9;    
  27.         }    
  28.      
  29.         while ((value.Input - 5) >= 0)    
  30.         {    
  31.             value.Output += "V";    
  32.      
  33.             value.Input -= 5;    
  34.         }    
  35.      
  36.         while ((value.Input - 4) >= 0)    
  37.         {    
  38.             value.Output += "IV";    
  39.      
  40.             value.Input -= 4;    
  41.         }    
  42.      
  43.         while ((value.Input - 3) >= 0)    
  44.         {    
  45.             value.Output += "III";    
  46.      
  47.             value.Input -= 3;    
  48.         }    
  49.      
  50.         while ((value.Input - 2) >= 0)    
  51.         {    
  52.             value.Output += "II";    
  53.      
  54.             value.Input -= 2;    
  55.         }    
  56.      
  57.         while ((value.Input - 1) >= 0)    
  58.         {    
  59.             value.Output += "I";    
  60.      
  61.             value.Input -= 1;    
  62.         }    
  63.     }    
  64. }    
  65.      
  66. public class RomanTenExpression : Expression    
  67. {    
  68.     public override void Interpret(RomanContext value)    
  69.     {    
  70.         while ((value.Input - 90) >= 0)    
  71.         {    
  72.             value.Output += "XC";    
  73.      
  74.             value.Input -= 90;    
  75.         }    
  76.      
  77.         while ((value.Input - 50) >= 0)    
  78.         {    
  79.             value.Output += "L";    
  80.      
  81.             value.Input -= 50;    
  82.         }    
  83.      
  84.         while ((value.Input - 40) >= 0)    
  85.         {    
  86.             value.Output += "XL";    
  87.      
  88.             value.Input -= 40;    
  89.         }    
  90.      
  91.         while ((value.Input - 30) >= 0)    
  92.         {    
  93.             value.Output += "XXX";    
  94.      
  95.             value.Input -= 30;    
  96.         }    
  97.      
  98.         while ((value.Input - 20) >= 0)    
  99.         {    
  100.             value.Output += "XX";    
  101.      
  102.             value.Input -= 20;    
  103.         }    
  104.      
  105.         while ((value.Input - 10) >= 0)    
  106.         {    
  107.             value.Output += "X";    
  108.      
  109.             value.Input -= 10;    
  110.         }    
  111.     }    
  112. }    
In the preceding example one class is responsible for interpreting the numbers 1 to 9 while the second handles 10 to 90. So if we combine them we can parse numbers from 1 to 99 as in the following code snippet:
  1. Expression[] expressions = new Expression[]    
  2. {    
  3.     new RomanTenExpression(),    
  4.     new RomanOneExpression(),    
  5. };    
  6.      
  7. var context = new RomanContext(99);    
  8.      
  9. foreach (var expression in expressions)    
  10. {    
  11.     expression.Interpret(context);    
  12. }    
  13.      
  14. context.Output; // "XCIX"  
Other practical uses could be parsing source code, or an “engrish sentençe” (did you mean “English sentence”?) and so on.