mirror of
https://github.com/rjNemo/design-patterns
synced 2026-06-06 02:26:40 +00:00
add code example
This commit is contained in:
parent
958fea5cf0
commit
1826234874
3 changed files with 125 additions and 0 deletions
53
behavioral/visitor/component.py
Normal file
53
behavioral/visitor/component.py
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
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"
|
||||
26
behavioral/visitor/main.py
Normal file
26
behavioral/visitor/main.py
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
from typing import List
|
||||
|
||||
from behavioral.visitor.component import Component, ConcreteComponentA, ConcreteComponentB
|
||||
from behavioral.visitor.visitor import Visitor, ConcreteVisitor1, ConcreteVisitor2
|
||||
|
||||
|
||||
def client_code(components: List[Component], visitor: Visitor):
|
||||
"""
|
||||
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)
|
||||
46
behavioral/visitor/visitor.py
Normal file
46
behavioral/visitor/visitor.py
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
from abc import ABC, abstractmethod
|
||||
|
||||
from behavioral.visitor.component import ConcreteComponentA, ConcreteComponentB
|
||||
|
||||
|
||||
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: ConcreteComponentA) -> None:
|
||||
print(f"{element.exclusive_method_of_concrete_component_a()} + ConcreteVisitor1")
|
||||
|
||||
def visit_concrete_component_b(self, element: ConcreteComponentB) -> None:
|
||||
print(f"{element.special_method_of_concrete_component_b()} + ConcreteVisitor1")
|
||||
|
||||
|
||||
class ConcreteVisitor2(Visitor):
|
||||
def visit_concrete_component_a(self, element: ConcreteComponentA) -> None:
|
||||
print(f"{element.exclusive_method_of_concrete_component_a()} + ConcreteVisitor2")
|
||||
|
||||
def visit_concrete_component_b(self, element: ConcreteComponentB) -> None:
|
||||
print(f"{element.special_method_of_concrete_component_b()} + ConcreteVisitor2")
|
||||
Loading…
Reference in a new issue