Back to: Design Patterns in C# With Real-Time Examples
Visitor Design Pattern in C# with Real-Time Example
In this article, I am going to discuss the Visitor Design Pattern in C# with Examples. Please read our previous article where we discussed the Command Design Pattern in C# with Examples. The Visitor Design Pattern falls under the category of Behavioural Design Pattern. As part of this article, we are going to 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 which changes the executing algorithm of an element object. 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.
To understand the above explanation better, please have a look at the following diagram. On the left-hand side, you can see visitor objects and 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). Now if you want to perform some distinct operation on each element, then you need to use the visitor design pattern. 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 on each element. If still, this is not clear at the moment then 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 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, what the school management has done is appoint 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.
In the same manner, one school bag sales company wants to promote its school bag. So, the company communicates with the school management and decided to give a school bag to each kid 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#?
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 with the name IElement.cs and then copy and paste the following code into it. 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 going to implement the IElement interface and provide implementations for the Accept method that takes a visitor as an argument. So, create a class file with the name Kid.cs and then copy and paste the following code into it. The following code is self-explained, so please go through the comment lines for a better understanding.
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 which implements the IElement Interface. So, create an interface with the name IVisitor.cs and then 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 are going to be concrete classes and these classes 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 with the name Doctor.cs and then copy and paste the following code into it. 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 is taking the IElement i.e. Kid as a parameter and then checks the health of that kid. And we need to call this Visit method for each kid in the school. The following class code is self-explained, so please go through the comment lines for a better understanding.
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 with the name Salesman.cs and then copy and paste the following code into it. 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 the school bag as a gift to 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 is taking the IElement i.e. Kid as a parameter and then give a school bag to that kid as a gift. And we need to call this Visit method for each kid in the school. The following example code is self-explained, so please go through the comment lines for a better understanding.
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 with the name School.cs and then copy and paste the following code into it. The Object Structure can enumerate its elements and may provide a high-level interface to allow 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 for each element, it is called the Accept method on the visitor object. If we are passing the Concrete Doctor visitor object, then it is going to call the Accept method which is defined in the Concrete Doctor visitor class. Similarly, if we are passing the Concrete Salesman visitor object, then it is going to call the Accept method which is defined in the Concrete Salesman visitor class. The following code is self-explained, so please go through the comment lines for a better understanding.
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 are creating the School instance and then creating the visitor1 instance i.e. Doctor, and then calling 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. The following class code is self-explained, so please go through the comment lines for a better understanding.
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 perform their operations.
Visitor Design Pattern UML or Class Diagram:
Let us understand the Class Diagram or UML Diagram of the Visitor Design Pattern and understand the different 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 is going to be an interface and it declares the Visit operation for each element in the object structure (i.e. for concrete visitors).
- ConcreteVisitor (Doctor, Salesman): These are the subclasses that 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 is an interface that 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 is a class that holds all the elements (i.e. a collection of kids) and provides a high-level interface that allows the visitor to visit all the elements.
- Client: This is a class that has access to the data structure objects and can instruct them to accept a Visitor to perform the appropriate operations. In our example, it is the Main method of the Program class.
When to use Visitor Design Pattern in C#?
- An object structure must have many unrelated operations to perform on it.
- An object structure cannot change but operations performed on it can change.
- The operations need to perform on the concrete classes of an object structure.
- Exposing the internal state or operations of the object structure is acceptable.
- Operations should be able to operate on multiple object structures that implement the same interface.
In the next article, I am going to discuss the Strategy Design Pattern in C# with Examples. Here, in this article, I try to explain the Visitor Design Pattern in C# with Examples. I hope you understood the need and use of the Visitor Design Pattern in C#.
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.