Visitor Pattern with Real Time Example

Scenarios in which visitor pattern is used:

Engineers use Visitor pattern in scenarios in which we need to extend a functionality to classes that implement an interface. But we don’t want to make any modification to the classes. Creating extension method can be a solution to the same. But at intermediate level, the extension method adds up to the same class itself. That may create a possibility of adding bugs to enterprise level applications.

Also, we use visitor pattern in scenarios in which you create a library for your code and create an extension for your classes but want to give the library user the flexibility to visit the class and use the data to extend a feature/method.

Real time example:

Suppose you have a application in which sends notifications in the form of Email/SMS/push Notification. All the classes to send notification (EmailNotification, SMSNotification, PushNotification) implement an interface INotification using a send method. Now you need to add logging each time a notification is sent. But the logging for email is in the email server and for SMS is in the SMS server using the APIs provided by the Email and SMS libraries respectively.

Existing Code without changes in C#:

 interface INotification
 {
     public void SendNotification();
 }
public class SMSNotification : INotification
{
    public void SendNotification()
    {
        //SMS Notification Code
    }
}

public class PushNotification : INotification
{
    public void SendNotification()
    {
        //Push Notification Code
    }
}

Now you can simply add a method to the interface named LogNotification and implement it in the concrete classes, but since we can’t modify the classes, we can use the visitor pattern.

The Solution (Using Visitor Pattern)

We just need to add a visitor method to each concrete class. Also, do not need to make any real implementation in that method, instead, just invoke the visitor to do the real work

    public interface INotification
    {
        public void SendNotification();
        public void accept(Visitor visitor);
    }

    public class EmailNotification : INotification
    {
        public void SendNotification()
        {
            //Email Notification Code
        }
        public void accept(Visitor visitor)
        {
            visitor.visit(this);
        }

    }

    public class SMSNotification : INotification
    {
        public void SendNotification()
        {
            //SMS Notification Code
        }

        public void accept(Visitor visitor)
        {
            visitor.visit(this);
        }

    }

    public class PushNotification : INotification
    {
        public void SendNotification()
        {
            //Push Notification Code
        }

        public void accept(Visitor visitor)
        {
            visitor.visit(this);
        }
    }

Now, we create a visitor class to Actually do the implementation:

    public interface Visitor
    {
        public void visit(INotification notification);
    }


    public class LogVisitor : Visitor
    {
        public void visit(INotification notification)
        {
            if(notification is EmailNotification)
            {
                //Log to Email Server
            }
            else if(notification is SMSNotification)
            {
                // Log to SMS Server
            }
            else if(notification is PushNotification)
            {
                // log to Push Notification Server
            }
        }
    }

Below is the code to invoke the above implementation:

    class Program
    {
        static void Main(string[] args)
        {
            INotification notificationToEmail = new EmailNotification();
            INotification notificationToSMS = new SMSNotification();
            INotification notificationToPush = new PushNotification();

            Visitor visitor = new LogVisitor();

            notificationToEmail.SendNotification();
            notificationToEmail.accept(visitor);

            notificationToSMS.SendNotification();
            notificationToSMS.accept(visitor);

            notificationToPush.SendNotification();
            notificationToPush.accept(visitor);

        }
    }


UML Diagram

Please let us know if you have any queries/suggestions in the comment box.

Leave a Comment

Your email address will not be published.