Sobes.tech
Middle+

What is the 'Visitor' design pattern?

sobes.tech AI

Answer from AI

The 'Visitor' design pattern allows adding new operations (visitors) to an existing object hierarchy (elements) without changing their structure.

# Element interface
class Element:
    def accept(self, visitor):
        pass

# Concrete elements
class ConcreteElementA(Element):
    def accept(self, visitor):
        visitor.visit_concrete_element_a(self)

    def operation_a(self):
        return "Operation A"

class ConcreteElementB(Element):
    def accept(self, visitor):
        visitor.visit_concrete_element_b(self)

    def operation_b(self):
        return "Operation B"

# Visitor interface
class Visitor:
    def visit_concrete_element_a(self, element):
        pass

    def visit_concrete_element_b(self, element):
        pass

# Concrete visitors
class ConcreteVisitor1(Visitor):
    def visit_concrete_element_a(self, element):
        print(f"Visitor 1 visiting {element.__class__.__name__}: {element.operation_a()}")

    def visit_concrete_element_b(self, element):
        print(f"Visitor 1 visiting {element.__class__.__name__}: {element.operation_b()}")

class ConcreteVisitor2(Visitor):
    def visit_concrete_element_a(self, element):
        print(f"Visitor 2 visiting {element.__class__.__name__} differently: {element.operation_a().upper()}")

    def visit_concrete_element_b(self, element):
        print(f"Visitor 2 visiting {element.__class__.__name__} differently: {element.operation_b().upper()}")

# Usage
elements = [ConcreteElementA(), ConcreteElementB()]
visitor1 = ConcreteVisitor1()
visitor2 = ConcreteVisitor2()

for element in elements:
    element.accept(visitor1)

for element in elements:
    element.accept(visitor2)

Advantages:

  • Ease of adding new operations: A new operation is implemented as a new visitor class.
  • Separation of concerns: The logic of operations is separated from the structure of the objects they operate on.
  • Open for extension, closed for modification: New visitors can be added without changing element classes.

Disadvantages:

  • Hard to add new elements: Adding a new element class requires modifying all existing visitor classes.
  • Breaks encapsulation: Visitors often need access to the internal state of elements.

Applicability:

  • When there is a complex object structure and various unrelated operations need to be performed on them.
  • When new operations are frequently added, but the object structure remains relatively stable.
  • When it is necessary to avoid cluttering element classes with many operations.