Le Visiteur est un patron de conception comportemental qui permet d’ajouter de nouveaux comportements à une hiérarchie de classes sans modifier l’existant.
Découvrez pourquoi les visiteurs ne peuvent pas être remplacés par la surcharge de méthodes dans notre article Visiteur et double répartition .
Complexité :
Popularité :
Exemples d’utilisation : Le visiteur n’est pas un patron très répandu en Python à cause de sa complexité et de la rareté de ses cas d’utilisation.
Exemple conceptuel
Dans cet exemple, nous allons voir la structure du Visiteur . Nous allons répondre aux questions suivantes :
Que contiennent les classes ?
Quels rôles jouent-elles ?
Comment les éléments du patron sont-ils reliés ?
main.py: Exemple conceptuel
from __future__ import annotations
from abc import ABC, abstractmethod
from typing import List
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):
visitor.visit_concrete_component_b(self)
def special_method_of_concrete_component_b(self) -> str:
return "B"
class Visitor(ABC):
"""
The Visitor Interface declares a set of visiting methods that correspond to
component classes. The signature of a visiting method allows the visitor to
identify the exact class of the component that it's dealing with.
"""
@abstractmethod
def visit_concrete_component_a(self, element: ConcreteComponentA) -> None:
pass
@abstractmethod
def visit_concrete_component_b(self, element: ConcreteComponentB) -> None:
pass
"""
Concrete Visitors implement several versions of the same algorithm, which can
work with all concrete component classes.
You can experience the biggest benefit of the Visitor pattern when using it with
a complex object structure, such as a Composite tree. In this case, it might be
helpful to store some intermediate state of the algorithm while executing
visitor's methods over various objects of the structure.
"""
class ConcreteVisitor1(Visitor):
def visit_concrete_component_a(self, element) -> None:
print(f"{element.exclusive_method_of_concrete_component_a()} + ConcreteVisitor1")
def visit_concrete_component_b(self, element) -> None:
print(f"{element.special_method_of_concrete_component_b()} + ConcreteVisitor1")
class ConcreteVisitor2(Visitor):
def visit_concrete_component_a(self, element) -> None:
print(f"{element.exclusive_method_of_concrete_component_a()} + ConcreteVisitor2")
def visit_concrete_component_b(self, element) -> None:
print(f"{element.special_method_of_concrete_component_b()} + ConcreteVisitor2")
def client_code(components: List[Component], visitor: Visitor) -> None:
"""
The client code can run visitor operations over any set of elements without
figuring out their concrete classes. The accept operation directs a call to
the appropriate operation in the visitor object.
"""
# ...
for component in components:
component.accept(visitor)
# ...
if __name__ == "__main__":
components = [ConcreteComponentA(), ConcreteComponentB()]
print("The client code works with all visitors via the base Visitor interface:")
visitor1 = ConcreteVisitor1()
client_code(components, visitor1)
print("It allows the same client code to work with different types of visitors:")
visitor2 = ConcreteVisitor2()
client_code(components, visitor2)
Output.txt: Résultat de l’exécution
The client code works with all visitors via the base Visitor interface:
A + ConcreteVisitor1
B + ConcreteVisitor1
It allows the same client code to work with different types of visitors:
A + ConcreteVisitor2
B + ConcreteVisitor2
Visiteur dans les autres langues