Visitor Pattern in Python…



This content originally appeared on DEV Community and was authored by Somenath Mukhopadhyay

Visitor design pattern allows the addition of completely different functionalities to an existing class without much alteration in the original class.

Let me explain it with an example.

Suppose there are two items a shop sells – Book and Medicine

Now say, normally these two Item classes would look like two – what we call in Java as POJO classes where the most important attribute will be the price.

So far so good.

Now suppose the government is running

– one literacy mission

and

– one Health mission

Under these missions, few books are given huge discounts, and few medicines are sold at discounted prices.

Without the Visitor pattern, the algorithm of the discounts would have been put inside the POJO classes which might create maintenance problems in the future when the algorithm for discount changes.

With the visitor pattern, we encapsulate all these discount algorithms inside a special method called visit which comes from a Visitor interface.

So if it is a LiteracyMissionVisitor, the special algorithm offers a discount on special books whereas if it is a HealthMissionVisitor, the discount goes to specific medicines – all we have to do is to call accept on these special Book and Medicine objects passing the proper Visitor object,

That’s it…

The UML class diagram looks as follows:

And here goes the source code of this Visitor Pattern

from abc import ABC, abstractmethod  

class Visitor(ABC):  
    @abstractmethod  
    def visit(self, book):  
        pass  
    @abstractmethod  
    def visit(self, medicine):  
        pass  

class Visitable(ABC):  
    @abstractmethod  
    def accept(self, visitor):  
        pass  

class Book(Visitable):  
    def __init__(self, price):  
        self.price = price  
    def accept(self, visitor):  
        return visitor.visit(self)  

    def getPrice(self):  
        return self.price  

class Medicine(Visitable):  
    def __init__(self, price):  
        self.price = price  

    def accept(self, visitor):  
        return visitor.visit(self)  

    def getPrice(self):  
        return self.price  

class LiteracyMissionVisitor(Visitor):  
    def __init__(self, percentagediscountOnBook):  
        self.discount = percentagediscountOnBook  
    def visit(self, book):  
        book.price = book.price - (book.price * self.discount)/100  
        return book.price  

class HealthMissionVisitor(Visitor):  
    def __init__(self, percentagediscountOnMedicine):  
        self.discount = percentagediscountOnMedicine  

    def visit(self, medicine):  
        medicine.price = medicine.price - (medicine.price * self.discount)/100  
        return medicine.price  




# Press the green button in the gutter to run the script.  
if __name__ == '__main__':  

    literacyMissionVisitor = LiteracyMissionVisitor(50)  

    chandaMama = Book(100)  

    print("Original price of the book is ", chandaMama.getPrice())  

    print("Due to literacy mission, there is huge discount on the book. 


        After discount, the price is ", chandaMama.accept(literacyMissionVisitor))  

    healthDriveVisitor = HealthMissionVisitor(70)  

    vitaminDCapsule = Medicine(200)  

    print("Original price of the medinine is ", vitaminDCapsule.getPrice())  

    print("Due to health  mission the reduced price of the 


            medicine is ", vitaminDCapsule.accept(healthDriveVisitor))  

If we run this program, the output will be as follows:

Original price of the book is 100

Due to literacy mission, there is huge discount on the book. After discount, the price is 50.0

Original price of the medinine is 200

Due to health mission the reduced price of the medicine is 60.0


This content originally appeared on DEV Community and was authored by Somenath Mukhopadhyay