Back to: Design Patterns in C# With Real-Time Examples
Visitor Design Pattern in C# with Examples
In this article, I will discuss the Visitor Design Pattern in C# with Examples. Please read our previous article discussing the Command Design Pattern in C# with Examples. The Visitor Design Pattern falls under the category of Behavioral Design Pattern. As part of this article, we will discuss the following pointers related to the Visitor Design Pattern in detail.
- What is the Visitor Design Pattern?
- Real-Time Examples to Understand Visitor Design Patterns.
- Implementing the Visitor Design Pattern in C#.
- Understanding the UML Diagram of Visitor Design Pattern.
- When to use Visitor Design Pattern in C#?
What is the Visitor Design Pattern?
In the Visitor Design Pattern, we use a Visitor object that changes an element object’s executing algorithm. In this way, when the visitor varies, the execution algorithm of the element object can also vary. As per the Visitor Design Pattern, the element object has to accept the visitor object so that the visitor object handles the operation on the element object.
The Visitor Design Pattern should be used when you have distinct and unrelated operations to perform across a structure of objects (element objects). That means the Visitor Design is used to create and perform new operations on a set of objects without changing the object structure or classes.
Example to Understand Visitor Design Pattern
To better understand the Visitor Design Pattern, please look at the following diagram. You can see visitor objects; on the right-hand side, you have the object structure. The object structure can be a collection of types, either Array, List, ArrayList, etc. As you can see, the object structure (collection) can have multiple elements (i.e., Element 1, Element 2, Element 3, and Element 4). You need to use the visitor design pattern to perform some distinct operations on each element. Here, each Visitor object will visit each element of the object structure and perform a distinct operation.
Now, it is possible to vary the operation as the visitor varies. For example, for Visitor 1, you may perform operation A on each element, whereas for Visitor 2, you may perform operation B. If this is unclear, don’t worry; we will try to understand the above explanation with some real-time examples.
Real-Time Example to Understand Visitor Design Pattern:
Let us understand the Visitor Design Pattern with one Real-Time Example. Please have a look at the following image. Here, we have a school, and in school, lots of kids are studying. One day, the school management decided to perform a health checkup for all the kids. So, the school management has appointed one child specialist doctor. What the doctor will do is he will visit the school and check the health of each and every kid. Once he has checked the health of each kid, then he provides the reports to the school management.
So, here in this example, the doctor is nothing but a visitor, and the object structure is the collection of Kids where each kid is an element object.
Similarly, one school bag sales company wants to promote its school bag. So, the company communicated with the school management and gave each kid a school bag as a gift. So, the company salesman visits the school and gives a school bag to each kid. For a better understanding, please have a look at the following diagram.
Here, the salesman is the visitor, and the object structure is the same collection of kids, where each kid is an element.
How to Implement Visitor Design Pattern in C#?
The Visitor design pattern allows you to add further operations to objects without modifying them. This pattern is particularly useful when you have a structure of many different types of objects, and you need to perform operations on these objects that are not suitable to be part of their class definitions. Here’s a basic outline of the Visitor design pattern:
- Element: This represents an element of an object structure. It provides an Accept method that takes a visitor as an argument.
- ConcreteElement: This is a concrete class that implements the Element interface.
- Visitor: This interface declares a visit operation for each class of ConcreteElement.
- ConcreteVisitor: This is a concrete class that implements the Visitor interface.
Let us implement the above-discussed example using the Visitor Design Pattern in C# step by step.
Step 1: Creating Element interface
The Element interface declares an Accept method that should take the base visitor interface as an argument. Create an interface named IElement.cs and copy and paste the following code. This interface declares one method called Accept, which takes the base Visitor interface as an argument.
namespace VisitorDesignPattern { // The Element interface declares an Accept method that should take the // base visitor interface as an argument. public interface IElement { void Accept(IVisitor visitor); } }
Note: Later, we are going to declare the base interface IVisitor.
Step 2: Creating Concrete Elements
The Concrete Element will implement the IElement interface and provide implementations for the Accept method that takes a visitor as an argument. So, create a class file named Kid.cs and copy and paste the following code.
namespace VisitorDesignPattern { // The Concrete Element implements the Accept operation that takes a visitor as an argument public class Kid : IElement { //The following Property is going to hold the Kid Name public string KidName { get; set; } //Initializing the KidName Property using Class Constructor public Kid(string name) { KidName = name; } //The following Method will call the Concrete Visitor Visit method by passing the current Kid Object public void Accept(IVisitor visitor) { visitor.Visit(this); } } }
Step 3: Creating the Visitor Interface
The Visitor Interface declares the Visit Method that corresponds to the Element class. The Visit Method will accept the IElement object as a parameter, i.e., the concrete class that implements the IElement Interface. So, create an interface with the name IVisitor.cs and copy and paste the following code into it.
namespace VisitorDesignPattern { // The Visitor Interface declares the Visit Method that corresponds to the Element class. // The Visit Method will accept the IElement object as a parameter i.e. the concrete class // which implements the IElement Interface. In this case the Kid object public interface IVisitor { void Visit(IElement element); } }
Step 4: Creating Concrete Visitors
These will be concrete classes, which must implement the IVisitor interface and provide implementations for the Visit method. Each concrete Visitor needs to implement the Visit method in their own way. The Concrete Visitors implement several versions of the same algorithm, which can work with all concrete component classes.
Concrete Visitor 1:
Create a class file named Doctor.cs, then copy and paste the following code. This Concrete Visitor class implements each operation declared by the IVisitor interface. This class has a property called Name, which is nothing but the doctor’s name who wants to check the health of each student. And we have initialized that Name property using the class constructor. It also implements the Visit method, and as part of the Visit method, it takes the IElement, i.e., Kid, as a parameter and then checks that kid’s health. And we need to call this Visit method for each kid in the school.
using System; namespace VisitorDesignPattern { // Concrete Visitors implement several versions of the same algorithm, which // can work with all concrete component classes. // The following Concrete Visitor class implements the Visit Method declared by Visitor Interface. // The Visit Method implements a fragment of the algorithm defined for the corresponding Element class. public class Doctor : IVisitor { //The following Property store the Name of the Doctor public string Name { get; set; } //Initializing the Name Property using Class Constructor public Doctor(string name) { Name = name; } //The Following is the Method we want to execute for each element of the collection or Data Structure public void Visit(IElement element) { Kid kid = (Kid)element; Console.WriteLine($"Doctor: {Name} did the health checkup of the child: {kid.KidName}"); } } }
Concrete Visitor 2:
Create a class file named Salesman.cs, then copy and paste the following code. This Concrete Visitor class also implements the operation defined by the IVisitor interface. This class has a property called Name, which is nothing but the Salesman’s name who wants to visit the school and give each student the school bag as a gift. And we have initialized that Name property using the class constructor. It also implements the Visit method, and as part of the Visit method, it takes the IElement, i.e., Kid, as a parameter and then gives a school bag to that kid as a gift. And we need to call this Visit method for each kid in the school.
using System; namespace VisitorDesignPattern { // The following Concrete Visitor class implements the Visit Method declared by Visitor Interface. // The Visit Method implements a fragment of the algorithm defined for the corresponding Element class. class Salesman : IVisitor { //The following Property store the Name of the Salesman public string Name { get; set; } //Initializing the Name Property using Class Constructor public Salesman(string name) { Name = name; } //The Following is the Method we want to execute for each element of the collection or Data Structure public void Visit(IElement element) { Kid kid = (Kid)element; Console.WriteLine($"Salesman: {Name} give a school bag to the child: {kid.KidName}"); } } }
Step 5: Creating Object Structure
Create a class file named School.cs and copy and paste the following code. The Object Structure can enumerate its elements and provide a high-level interface, allowing the Visitor to visit its elements. So, in the below code, you can see we have created a collection of List<IElement> elements variable and initialized that elements variable using the class constructor, i.e., initializing the elements variable with few elements. Here, the PerformOperation method plays an important role. The PerformOperation method takes one visitor object as a parameter, and then it is called the Accept method on the visitor object for each element. If we pass the Concrete Doctor visitor object, it will call the Accept method, defined in the Concrete Doctor visitor class. Similarly, if we pass the Concrete Salesman visitor object, it will call the Accept method, defined in the Concrete Salesman visitor class.
using System.Collections.Generic; namespace VisitorDesignPattern { // ObjectStructure // The ObjectStructure contains the list of elements that a visitor wants to visit public class School { private static readonly List<IElement> Elements = new List<IElement>(); static School() { Elements = new List<IElement> { new Kid("Ram"), new Kid("Sara"), new Kid("Pam") }; } //The following Method Accepts the Concrete Visitor Object as a Parameter public void PerformOperation(IVisitor visitor) { // Loop Through Each Element of the Collection or Data Structure foreach (var kid in Elements) { //Calling Accept Method of the Element Object by passing the Visitor Object as an argument kid.Accept(visitor); } } } }
Step 6: Client Code
The Main method of the Program class is going to be the Client. So, modify the Main method of the Program class as shown below. Here, you can see. First, we create the School instance and then create the visitor1 instance, i.e., Doctor, and then call the PerformOperation method of the School instance by passing the visitor1 instance as a parameter. And we have done the same thing with the visitor2, i.e., Salesman.
using System; namespace VisitorDesignPattern { class Program { static void Main(string[] args) { //Create an instance of the object structure i.e. School class School school = new School(); //Create an Instance of the Visitor i.e. Doctor var visitor1 = new Doctor("James"); //Call the PerformOperation Method by passing the Visitor Object which wants to Visit //All elements of the ObjectStructure i.e. a collection //Here, Doctor James will Visit all the Kids at the School school.PerformOperation(visitor1); Console.WriteLine(); //Create an Instance of another Visitor i.e. Salesman var visitor2 = new Salesman("John"); //Call the PerformOperation Method by passing the Visitor Object which wants to Visit //All elements of the ObjectStructure i.e. a collection //Here, the Salesman John will Visit all the Kids of the School school.PerformOperation(visitor2); Console.Read(); } } }
Output:
In short, here we created two visitors (visitor1 and visitor2), and they visited each and every kid in the school and performed their operations.
Use Cases of Visitor Design Pattern:
- When you need to perform operations on a set of objects with different classes and you want to avoid type checks.
- When new operations need to be added to complex class hierarchies without changing the classes themselves.
Visitor Design Pattern UML or Class Diagram:
Let us understand the Class Diagram or UML Diagram of the Visitor Design Pattern and the components involved. Please have a look at the following image.
As you can see in the above image, the Visitor Design Pattern consists of six components. They are as follows:
- Visitor (IVisitor): This interface will declare the Visit operation for each element in the object structure (i.e., for concrete visitors).
- ConcreteVisitor (Doctor, Salesman): These subclasses implement each operation declared by the IVisitor interface. Each operation implements a fragment of the algorithm defined for the corresponding class or object in the structure.
- Element (IElement): This interface defines an Accept operation that takes a visitor as an argument.
- ConcreteElement (Kid): This is a class that implements the Element (i.e., IElement) interface, i.e., this class implements the Accept operation that takes a visitor as an argument.
- ObjectStructure (School): This class holds all the elements (i.e., a collection of kids) and provides a high-level interface that allows visitors to visit all the elements.
- Client: This class can access the data structure objects and instruct them to accept a Visitor to perform the appropriate operations. In our example, it is the Main method of the Program class.
In the next article, I will discuss the Real-Time Examples of the Visitor Design Pattern in C#. In this article, I try to explain the Visitor Design Pattern in C# with Examples. I hope you understand the need and use of the Visitor Design Pattern in C#.
Registration Open For New Online Training
Enhance Your Professional Journey with Our Upcoming Live Session. For complete information on Registration, Course Details, Syllabus, and to get the Zoom Credentials to attend the free live Demo Sessions, please click on the below links.
The whole set of tutorials about patterns is very nice to use as a reference! Would it be possible to include a UML design demonstrating what the pattern look like?
Hi
Thanks for your valuable feedback. We have updated the content and added the UML diagrams.