Object Oriented Software – Visitor Pattern

Visitor pattern is  a behavioral pattern that allows addition of new features to a class without actually modifying the class. Visitor pattern is one way of implementing the Open/ Close principle (which is one of the SOLID principles).

Lets learn more about this pattern using an example. Say we are a software company and one of our clients wants us to develop a simple tool that allows the end-user to draw geometric shapes and save them to a file. At the time of save, the user should have the option to specify the file format. The tool should support the shapes – Circle, Square and the formats – png, jpeg. Lets see how we can go about developing the tool.

We can create an abstract class called Shape. We will need separate methods for saving files in different formats for each shape. This is so because each format will require its own set of variables and logic to write to a file which can vary depending on the shape.

class Shape{
    protected:
    string name;
    virtual void draw()=0;//draws the shape on the canvas
    virtual saveAsPng()=0;//saves the file with .png extension
    virtual saveAsJpeg()=0;//saves the file with .jpeg extension
};

Circle and Square will need to extend the Shape class and implement all of its methods.

class Circle: public Shape{
    public:
    Circle(){name = "Circle";}
    draw();
    saveAsPng();
    saveAsJpeg();
};

class Square : public Shape{
public:
    Square(){name = "Square";}
    draw();
    saveAsPng();
    saveAsJpeg();
};

Everything is perfect. We designed and developed the tool, tested the features and gave our tool to the client and they were happy, end of story!.

Not really! After a few months, our client wants us to add more file formats to the tool. Now, we need to modify all of our classes – Shape, Circle and Square. We need to add a new method for the new file format in all of these classes. Imagine the situation if we had several shapes instead of the two. Anyway, we go through the pain, modify the classes and deliver the tool to the client.

Again after some months, they want the tool to support additional file formats. It is high time we realized that the client requirements are perennial. It is not practical for us to modify all of the classes each time our client approaches us with a new requirement. So the best option would be to change the design of the tool so that new changes can be incorporated with little effort. This is where Visitor Pattern can help us.

After we re-design our tool as per the visitor pattern, the classes would look as shown below.

class Shape{
    protected:
    string name;
    virtual void draw()=0; // draws the shape on the canvas
    virtual accept(SaveTypeVisitor visitor) = 0;
};

class Circle: public Shape{
    public:
    Circle(){name = "Circle";}
    draw();
    accept(SaveTypeVisitor visitor){
        visitor.visit(this);
    }
};

class Square : public Shape{
    public:
    Square(){name = "Square";}
    draw();
    accept(SaveTypeVisitor visitor){
        visitor.visit(this);
    }
};

class saveTypeVisitor{
    protected:
    virtual visit(Shape shape)=0;
};


class pngTypeVisitor:public saveTypeVisitor{
    public:
    visit(Shape shape){
        if(shape.name == "Circle"){
            //do Something
        }
        else if (shape.name=="Square"){
            //do Something
        }
    }
};


class pngTypeVisitor:public saveTypeVisitor{
public:
    visit(Shape shape){
        if(shape.name == "Circle"){
            //do Something
        }
        else if (shape.name=="Square"){
            //Do Something
        }
    }
};

As you can see, there are a few new classes in our revamped design. If you observe closely, any new file format can now be easily implemented in the shape classes without even touching them. We will only need to create a single new class by extending the saveTypeVisitor.

If the end-user wants to save Circle in a .png format, we can call the accept() method of the Circle class with pngTypeVisitor as its argument.

Therefore , visitor pattern consists of two types of classes: visitor class and element class. In our example,  saveTypeVisitor is the abstract visitor class and pngTypeVisitor and jpegTypeVisitor are its extensions whereas Shape is the abstract element class and Circle and Sqaure are its extensions.  Visitor pattern lets us define new features in element classes with the help of visitor classes without making any changes to the element classes.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s