Interpreter Pattern Code Review

Define the Element Base Class and Associated Child Clases

Code Download

Code Review

Code Walkthrough

Define the Element class which contains all the core functions to be used in this pattern. All other classes will derive from this class.

class Element { public Int32 Weight { get; set; } public Byte Level { get; set; } public Element Next { get; set; } public Element Child { get; set; }
public static Int32 SumLab { get; set; } public static Int32 SumTest { get; set; }
public static Int32[] m_values; public static Int32 m_counter; private static Byte m_level = 1;
public virtual String Display() { return (String.Concat(this.Weight, "%")); } public void OutputResults(Context context, Int32[] values) { context.Output = 0; m_values = values; m_counter = 0;
this.ParseResults(context); } public void Print() { switch (this.Level) { case 0: Console.WriteLine("{0}", this); break; case 1: Console.WriteLine("\t{0} {1}", this, this.Weight); break; case 2: Console.WriteLine("\t\t{0} {1}", this, this.Weight); break; } if (this.Child != null) { this.Child.Next.Print(); } if (this.Next != null) { this.Next.Print(); } } public void Summarize() { if (this is Lab) { SumLab += this.Weight; } else if (this is Test) { SumTest += this.Weight; } else if (((this is MidTerm) || (this is Exam)) && (this.Child == null)) { SumTest += this.Weight; } if (this.Child != null) { this.Child.Next.Summarize(); } if (this.Next != null) { this.Next.Summarize(); } } public void Parse(Context context) { String validInput = "LTME"; Char element = Char.MinValue;
if (context.Input.Length > 0) { if (validInput.IndexOf(context.Input[0]) >= 0) { element = context.Input[0]; } } if (element != Char.MinValue) { switch (element) { case 'L': this.Next = new Lab(); break;
case 'T': this.Next = new Test(); >break;
case 'M': this.Next = new MidTerm(); break;
case 'E': this.Next = new Exam(); break; } this.Next.Weight = this.ParseNumber(context); this.Next.Level = m_level;
if (context.Input.Length > 0) { element = context.Input[0]; } if (element == '(') { context.Input = context.Input.Substring(1); this.Next.Child = new Element(); m_level++; this.Next.Child.Parse(context); m_level--;
Element e = this.Next.Child; while (e != null) { e.Weight = e.Weight * this.Next.Weight / 100; e = e.Next; } if (context.Input.Length >= 2) { context.Input = context.Input.Substring(2); } else { context.Input = context.Input.Substring(1); } } else { this.Next.Child = null; } this.Next.Parse(context); } } private Int32 ParseNumber(Context context) { Int32 posX = context.Input.IndexOf('|'); Int32 value = Int32.Parse(context.Input.Substring(1, posX - 1)); context.Input = context.Input.Substring(posX + 1); return (value); } private void ParseResults(Context context) { if ((this is Lab) || (this is Test)) { context.Output += m_values[m_counter] * this.Weight; m_counter++; } else if (((this is MidTerm) || (this is Exam)) && (this.Child == null)) { context.Output += m_values[m_counter] * this.Weight; m_counter++; } if (this.Child != null) { this.Child.ParseResults(context); } if (this.Next != null) { this.Next.ParseResults(context); } } }

The input data to this class is provided by the Context class, and is declared in a predefined grammatical syntax. The Parse() and ParseNumber() methods work on the input data to generate an object structure of objects derived from the Element class (object). These include Lab, Test, MidTerm and Exam objects.

Once the input data has been organised into the object structure, we can execute "interpreter" methods against the data to generate any outputs required. The ParseResults() method calculates ("interprets") student course results based on predefined weighting for each element of the course.

The Course class (object) represents the first element in the object structure. This class inherits from the Element class, and therefore inherits all the methods defined in the Element class.

class Course : Element { public String Name { get; set; }
public Course(Context context) { this.Name = context.Input.Substring(0, 6); context.Input = context.Input.Substring(7); }
public override String Display() { return (this.Name); } public override string ToString() { return "Course"; } }

The Lab class (object) represents another element in the object structure. This class inherits from the Element class, and therefore inherits all the methods defined in the Element class.

class Lab : Element { public override string ToString() { return "Lab"; } }

The Test class (object) represents another element in the object structure. This class inherits from the Element class, and therefore inherits all the methods defined in the Element class.

class Test : Element { public override string ToString() { return "Test"; } }

The MidTerm class (object) represents another element in the object structure. This class inherits from the Element class, and therefore inherits all the methods defined in the Element class.

class MidTerm : Element { public override string ToString() { return "Midterm"; } }

The Exam class (object) represents another element in the object structure. This class inherits from the Element class, and therefore inherits all the methods defined in the Element class.

class Exam : Element { public override string ToString() { return "Exam"; } }