Visitor – It allows the program changes the algorithm and the operations that base on the visitor to change, which means can separate the algorithms from objects on which they operate.

From Design Pattern – Behavioral Patterns

Structure

Visitor pattern – Class diagram UML

Applicability

  • Use this pattern when the program needs to operate on all elements of a complex object structure—for example, an object tree.
  • Use this pattern to clean up the business logic of auxiliary behaviors.
  • Use this pattern when the program’s behavior makes sense, only in some classes of a class hierarchy, but not in others.

Pros and Cons

PROS

  • Open-closed principle: The program can introduce a new behavior, which can work with objects of different classes without changing these objects.
  • Single responsibility principle: The program can move multiple versions of the same behavior into the same class object.
  • A visitor of the object can accumulate some helpful information while working with various things. It might be handy when the program wants to traverse some complex object structures, such as the object tree, and apply the visitor to each object of this structure.

CONS

  • The programs need to update all visitors each time a class gets added to or removed from the element hierarchy.
  • Visitors might lack the necessary access to the private fields and methods of the elements, which these are supposed to work.

How to Implement

#1 Basic Sample

static void Main(string[] args)
{
	DataStructure dataStructure = new DataStructure();
	dataStructure.Attach(new ConcreteComponentA());
	dataStructure.Attach(new ConcreteComponentB());

	Console.WriteLine("The client code works with all visitors via the base Visitor interface:");
	var Visitor1 = new ConcreteVisitor1();
	DataStructure.Accept(Visitor1);
	
	Console.WriteLine("It allows the same client code to work with different types of visitors:");
	var Visitor2 = new ConcreteVisitor2();
	DataStructure.Accept(Visitor2);

	Console.ReadKey();
}

class DataStructure
{
	private static List<IComponent> components = new List<IComponent>();

	public void Attach(IComponent component) => components.Add(component);

	public void Detach(IComponent component) => components.Remove(component);

	public static void Accept(IVisitor visitor)
	{
		foreach (IComponent component in components)
		{
			component.Accept(visitor);
		}
	}
}

interface IComponent
{
	void Accept(IVisitor visitor);
}

class ConcreteComponentA : IComponent
{
	public void Accept(IVisitor visitor)
	{
		visitor.VisitConcreteComponentA(this);
	}

	public string ExclusiveMethodOfConcreteComponentA() => "A";
}

class ConcreteComponentB : IComponent
{
	public void Accept(IVisitor visitor)
	{
		visitor.VisitConcreteComponentB(this);
	}
	
	public string SpecialMethodOfConcreteComponentB() => "B";
}

interface IVisitor
{
	void VisitConcreteComponentA(ConcreteComponentA element);
	void VisitConcreteComponentB(ConcreteComponentB element);
}

class ConcreteVisitor1 : IVisitor
{
	public void VisitConcreteComponentA(ConcreteComponentA element)
	{
		Console.WriteLine(element.ExclusiveMethodOfConcreteComponentA() + " + ConcreteVisitor1");
	}

	public void VisitConcreteComponentB(ConcreteComponentB element)
	{
		Console.WriteLine(element.SpecialMethodOfConcreteComponentB() + " + ConcreteVisitor1");
	}
}

class ConcreteVisitor2 : IVisitor
{
	public void VisitConcreteComponentA(ConcreteComponentA element)
	{
		Console.WriteLine(element.ExclusiveMethodOfConcreteComponentA() + " + ConcreteVisitor2");
	}

	public void VisitConcreteComponentB(ConcreteComponentB element)
	{
		Console.WriteLine(element.SpecialMethodOfConcreteComponentB() + " + ConcreteVisitor2");
	}
}

#2 Web Application Project

Step 1 Create three interface class files. One interface class file name sets “IVisitorServices.” Another file name sets “IVisitor.” Other file name sets “IVisitorComponent.” These files inherit the IDispose interface class.

Fig 1 IVisitorServices interface class file source code
Fig 2 IVisitor interface class file source code
Fig 3 IVisitorComponent interface class file source code

Step 2 Create two class object files about the “IVisitorComponent.” One class file name sets “ConcreteVisitorComponentA.” Other file name sets “ConcreteVisitorComponentB.” These files inherit the “IVisitorComponent.”

Fig 4 ConcreteVisitorComponentA & ConcreteVisitorComponentB class file source code

Step 3 Create two class object files about the “IVisitor.” One class file name sets “ConcreteVistor1.” Other file name set “ConcreteVisitor2.” These files are intended for use by the visitor viewpoint to watch other object class files and inherit the “IVisitor.”

Fig 5 ConcreteVistor1 & ConcreteVistor2 class file source code

Step 4 Create a class file named “VisitorObjStructure,” which means the business logic layer(BLL) connects to the visitor viewpoints who want to watch what kind of visitor component.

Fig 6 VisitorObjStructure class file source code

Step 5 Create the visitor pattern-related files in the web project, such as the controller files, the view flies, then register the “IVisitorServices” class files and the “VisitorServices” class files in the Startup.cs.

// Visitor
services.AddScoped(typeof(IVisitorServices<>), typeof(VisitorServices<>));
Fig 7 Visitor patterb result

Reference

Leave a Reply