Printed from www.rmfusion.com A Developer website designed for Developers

Visitor Pattern Code Review

Code Download

Define the Pattern Interface and Handler Objects

interface IVisitor { void Visit(Element element); }

This interface defines the Visit() method, which accepts the object to be visited as a parameter.

The PrintVisitor class (object) invokes the Accept() method on the class (object) to be visited.

class PrintVisitor : IVisitor { public void Print(Element element) { element.Accept(this);
if (element.Child != null) { Console.Write(" ["); Print(element.Child); } if (element.Next != null) { Print(element.Next); Console.Write("] "); } } public void Visit(Element element) { Console.Write(" {0}", element.Weight); } }

The visited class, in turn, invokes the Visit() method on the PrintVisitor class. The Visit() method contains the process (code) that needs to be executed against the visited class (object) each time the object is visited.

The StructureVisitor class (object) invokes the Accept() method on the class (object) to be visited.

class StructureVisitor : IVisitor { public Int32 Lab { get; set; } public Int32 Test { get; set; }
public void VisitAllLabTest(Element element) { element.Accept(this);
if (element.Child != null) { this.VisitAllLabTest(element.Child.Next); } if (element.Next != null) { this.VisitAllLabTest(element.Next); } } public void Visit(Element element) { if(((element is MidTerm) || (element is Exam)) && (element.Child==null)) { this.Test += element.Weight; return; } if (element is Lab) { this.Lab += element.Weight; return; } if (element is Test) { this.Test += element.Weight; return; } } }

The visited class, in turn, invokes the Visit() method on the StructureVisitor class. The Visit() method contains the process (code) that needs to be executed against the visited class (object) each time the object is visited.

Define the Element Interface and Handler Objects

Define the IElement abstract class to be used as the base class for all classes that can be visited.

abstract class IElement { public abstract void Accept(IVisitor visitor); }

This abstract class defines the Accept() method, which accepts the visitor object as a parameter.

The Element class (object) defines the base class for a type of class that can be visited and invokes the Visit() method on the visitor class (object).

class Element : IElement { public Int32 Weight { get; set; } public Element Next { get; set; } public Element Child { get; set; }
public override void Accept(IVisitor visitor) { visitor.Visit(this); } private Int32 GetNumber(Context context) { Int32 atSpace = context.Input.IndexOf(' '); Int32 number = Int32.Parse(context.Input.Substring(1, atSpace)); context.Input = context.Input.Substring(atSpace + 1); return (number); } public void Parse(Context context) { String starters = "LTME";
if ((context.Input.Length > 0) && (starters.IndexOf(context.Input[0]) >= 0)) { switch (context.Input[0]) { 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;
default: break; } this.Next.Weight = this.GetNumber(context); if ((context.Input.Length > 0) && (context.Input[0] == '(')) { context.Input = context.Input.Substring(1); this.Next.Child = new Element(); this.Next.Child.Parse(context); Element e = this.Next.Child; while (e != null) { e.Weight = e.Weight * this.Next.Weight / 100; e = e.Next; } context.Input = context.Input.Substring(2); } this.Next.Parse(context); } } }

The Course class (object) inherits from the Element base class and defines one type of class that can be visited.

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 void Accept(IVisitor visitor) { visitor.Visit(this); } }

The Course class invokes the Visit() method on the visitor class (object).

The Lab class (object) inherits from the Element base class and defines another type of class that can be visited.

class Lab : Element { public override void Accept(IVisitor visitor) { visitor.Visit(this); } }

The Lab class invokes the Visit() method on the visitor class (object).

The Test class (object) inherits from the Element base class and defines another type of class that can be visited.

class Test : Element { public override void Accept(IVisitor visitor) { visitor.Visit(this); } }

The Test class invokes the Visit() method on the visitor class (object).

The MidTerm class (object) inherits from the Element base class and defines another type of class that can be visited.

class MidTerm : Element { public override void Accept(IVisitor visitor) { visitor.Visit(this); } }

The MidTerm class invokes the Visit() method on the visitor class (object).

The Exam class (object) inherits from the Element base class and defines another type of class that can be visited.

class Exam : Element { public override void Accept(IVisitor visitor) { visitor.Visit(this); } }

The Exam class invokes the Visit() method on the visitor class (object).

Define the Context Object

The Context class (object) is a simple class that stores that input data to be used by the Element base class (object).

class Context { public String Input { get; set; }
public Context(String c) { this.Input = c; } }

Use the Visitor Pattern

The Program class creates an instance of the Context class (object) and this is passed to the Course class (object) where the data is parsed.

class Program { static void Main(string[] args) { String rules = "COS333 L2 L2 L2 L2 L2 M25 (L40 T60 ) L10 E55 (L28 T73 ) ";
Context context; Console.WriteLine("{0}\n", rules);
context = new Context(rules); Element course = new Course(context); course.Parse(context);
PrintVisitor visitor = new PrintVisitor(); Console.WriteLine("Visitor 1 - Course structure"); visitor.Print(course);
StructureVisitor visitor2 = new StructureVisitor(); visitor2.VisitAllLabTest(course); Console.WriteLine("\n\nVisitor 2 - Summing the weights\nLabs {0}% and Tests {1}%", visitor2.Lab, visitor2.Test);
Console.Read(); } }

Once the Context data has been parsed, the Course object is visited by the Visitor object and results output.