Visitor Design Pattern is a powerful and flexible pattern that allows you to define operations on an object structure without altering its classes. Let’s embark on a journey to understand the intricacies of the Visitor pattern and how it can enhance the flexibility and extensibility of your code.
Table of Contents
What?
The Visitor design pattern is a behavioural design pattern that allows you to add new behaviours to a group of classes without modifying their code. It provides a way to separate algorithms or operations from the object on which they operate.
Code
from abc import ABC, abstractmethod
# Element: Product (Abstract class)
class Product(ABC):
@abstractmethod
def accept(self, visitor):
pass
# Concrete Element: Electronics Product
class ElectronicsProduct(Product):
def __init__(self, price):
self.price = price
def accept(self, visitor):
visitor.visit_electronics(self)
# Concrete Element: Clothing Product
class ClothingProduct(Product):
def __init__(self, price):
self.price = price
def accept(self, visitor):
visitor.visit_clothing(self)
# Concrete Element: Book Product
class BookProduct(Product):
def __init__(self, price):
self.price = price
def accept(self, visitor):
visitor.visit_book(self)
# Visitor: Discount Calculator
class DiscountCalculatorVisitor:
def __init__(self):
self.total_discount = 0
def visit_electronics(self, electronics_product):
# Assume electronics discount calculation here
self.total_discount += electronics_product.price * 0.1
def visit_clothing(self, clothing_product):
# Assume clothing discount calculation here
self.total_discount += clothing_product.price * 0.2
def visit_book(self, book_product):
# Assume book discount calculation here
self.total_discount += book_product.price * 0.15
# Usage
if __name__ == "__main__":
electronics = ElectronicsProduct(500)
clothing = ClothingProduct(100)
book = BookProduct(30)
discount_calculator = DiscountCalculatorVisitor()
electronics.accept(discount_calculator)
clothing.accept(discount_calculator)
book.accept(discount_calculator)
print("Total discount:", discount_calculator.total_discount) # Total discount: 74.5
we have added new behaviours using DiscountCalculatorVisitor() to our Product classes
Use Case of the Visitor Design Pattern
- Document Parsing: It facilitates the separation of concerns between document elements and processing operations.
- GUI Components: Using the Visitor pattern, one can create visitor classes for each operation, ensuring that new functionalities can be seamlessly added without altering individual UI component classes. This promotes a clean separation of concerns and supports the open/closed principle.
- File System Processing:
In file system applications with diverse file types, such as documents, images, and videos, the Visitor pattern streamlines the addition of processing operations. Whether it’s indexing, compression, or encryption, creating visitor classes for each operation ensures that new functionalities can be introduced without modifying the existing file classes. This maintains a flexible and scalable design. - Game Development:
Game development scenarios benefit from the Visitor Design Pattern when dealing with different game objects like characters, enemies, and obstacles. By implementing visitor classes for rendering, collision detection, and AI behaviour, developers can seamlessly integrate new features into game objects without altering their individual classes. This approach supports the dynamic and evolving nature of game development. - Medical Information System:
In medical information systems, where patient records encompass diverse data types, the Visitor pattern enables the performance of operations like data analysis, report generation, and data export. Creating visitor classes for each operation allows for the seamless addition of new processing capabilities, ensuring that the system remains adaptable and extensible to evolving requirements.
Benefits of the Visitor Design Pattern
- Separation of Concerns: It promotes a separation between algorithms and the elements they operate on. By encapsulating operations in dedicated visitor classes, developers can focus on specific concerns within their code. This separation enhances readability and maintainability, allowing changes or additions to be made without affecting the core structure of the elements being visited.
- Open/Closed Principle: It facilitates the extension of code without modifying existing classes. New functionalities can be introduced by creating new visitor classes, ensuring that the existing code remains closed for modification. This principle encourages a modular and scalable design, where the system can evolve by adding new features through extensions rather than alterations.
Conclusion
We hope you’ve gained insights into its elegance and practicality as we conclude our exploration of the Visitor Design Pattern. By embracing the separation of concerns and promoting extensibility, the Visitor pattern stands as a valuable tool in the arsenal of any software designer. Happy coding!
Resources
For further exploration, make sure to check out these helpful resources: