import logging
from abc import ABC, abstractmethod
from typing import List
# Configure the logger
logger = logging.getLogger("visitor")
logger.setLevel(logging.INFO)
[docs]
class Visitor(ABC):
"""
Visitor interface declaring operations for different element types.
"""
[docs]
@abstractmethod
def visit_element_a(self, element: "ElementA") -> None:
"""
Visit an ElementA instance.
:param element: The ElementA instance.
"""
pass
[docs]
@abstractmethod
def visit_element_b(self, element: "ElementB") -> None:
"""
Visit an ElementB instance.
:param element: The ElementB instance.
"""
pass
[docs]
class Element(ABC):
"""
Abstract base class for elements.
"""
[docs]
@abstractmethod
def accept(self, visitor: Visitor) -> None:
"""
Accept a Visitor.
:param visitor: The Visitor to accept.
"""
pass
[docs]
class ElementA(Element):
"""
Concrete implementation of an element, ElementA.
"""
[docs]
def operation_a(self) -> str:
"""
Perform ElementA-specific behavior.
:return: A message describing the operation.
"""
return "ElementA operation."
[docs]
def accept(self, visitor: Visitor) -> None:
"""
Accept a Visitor.
:param visitor: The Visitor to accept.
"""
visitor.visit_element_a(self)
[docs]
class ElementB(Element):
"""
Concrete implementation of an element, ElementB.
"""
[docs]
def operation_b(self) -> str:
"""
Perform ElementB-specific behavior.
:return: A message describing the operation.
"""
return "ElementB operation."
[docs]
def accept(self, visitor: Visitor) -> None:
"""
Accept a Visitor.
:param visitor: The Visitor to accept.
"""
visitor.visit_element_b(self)
[docs]
class ConcreteVisitorA(Visitor):
"""
Concrete Visitor implementing specific operations for each element type.
"""
[docs]
def visit_element_a(self, element: ElementA) -> None:
"""
Visit an ElementA instance.
:param element: The ElementA instance to visit.
"""
logger.info(f"ConcreteVisitorA: {element.operation_a()}")
[docs]
def visit_element_b(self, element: ElementB) -> None:
"""
Visit an ElementB instance.
:param element: The ElementB instance to visit.
"""
logger.info(f"ConcreteVisitorA: {element.operation_b()}")
[docs]
class ConcreteVisitorB(Visitor):
"""
Another Concrete Visitor with different operations for each element type.
"""
[docs]
def visit_element_a(self, element: ElementA) -> None:
"""
Visit an ElementA instance.
:param element: The ElementA instance to visit.
"""
logger.info(f"ConcreteVisitorB: {element.operation_a()}")
[docs]
def visit_element_b(self, element: ElementB) -> None:
"""
Visit an ElementB instance.
:param element: The ElementB instance to visit.
"""
logger.info(f"ConcreteVisitorB: {element.operation_b()}")
[docs]
class ObjectStructure:
"""
ObjectStructure manages a collection of elements and processes them with visitors.
"""
[docs]
def __init__(self) -> None:
"""
Default constructor.
Initializes an empty list to store elements.
"""
self._elements: List[Element] = []
[docs]
def add_element(self, element: Element) -> None:
"""
Add an element to the structure.
:param element: The Element to add.
"""
self._elements.append(element)
[docs]
def accept(self, visitor: Visitor) -> None:
"""
Accept a visitor for all elements.
Iterates over all elements in the structure and calls their accept method with
the given visitor.
:param visitor: The Visitor to accept.
"""
for element in self._elements:
element.accept(visitor)