from __future__ import annotations from abc import ABC, abstractmethod # from behavioral.visitor.visitor import Visitor class Component(ABC): """ The Component interface declares an `accept` method that should take the base visitor interface as an argument. """ @abstractmethod def accept(self, visitor: "Visitor") -> None: pass class ConcreteComponentA(Component): """ Each Concrete Component must implement the `accept` method in such a way that it calls the visitor's method corresponding to the component's class. """ def accept(self, visitor: "Visitor") -> None: """ Note that we're calling `visitConcreteComponentA`, which matches the current class name. This way we let the visitor know the class of the component it works with. """ visitor.visit_concrete_component_a(self) def exclusive_method_of_concrete_component_a(self) -> str: """ Concrete Components may have special methods that don't exist in their base class or interface. The Visitor is still able to use these methods since it's aware of the component's concrete class. """ return "A" class ConcreteComponentB(Component): """ Same here: visitConcreteComponentB => ConcreteComponentB """ def accept(self, visitor: "Visitor") -> None: visitor.visit_concrete_component_b(self) def special_method_of_concrete_component_b(self) -> str: return "B"