This repository has been archived by the owner on Jan 2, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 32
/
visitor.py
109 lines (78 loc) · 2.69 KB
/
visitor.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
"""Visitor pattern
Visitor gives us the ability to add new operations to existing objects without
modifying these objects. It's one way to follow the open/closed principle.
"""
# classes that we cannot change (e.g. a fairly stable class hierarchy)
class Element(object):
pass
class ElementOne(Element):
pass
class ElementTwo(Element):
pass
class ElementThree(ElementOne, ElementTwo):
pass
class ElementFour(ElementThree):
pass
# Extrinsic Visitor
class Visitor(object):
operations = {
"ElementTwo": "custom_operation",
"ElementFour": "another_custom_operation",
}
def visit(self, element, *args, **kwargs):
"""Perform an operation specific for the passed element.
Steps:
1. traverse the class hierarchy of an Element object
2. discover what operation to perform on the Element object
3. perform the specific operation on the Element object
Parameters
----------
element : Element
object whose behavior must be implemented here
Returns
-------
return value/s of the method chosen at runtime
"""
method_name = "default_operation"
for cls in element.__class__.__mro__:
try:
method_name = self.operations[cls.__name__]
break # we found out a custom operation to perform, so we exit
except KeyError:
pass # keep default_operation if there isn't a custom one
method = getattr(self, method_name)
return method(element, *args, **kwargs)
# implement the behaviors for the Element objects
@staticmethod
def default_operation(elem, *args, **kwargs):
print(
"No custom operation defined for {} or its class hierarchy".format(
elem.__class__.__name__
)
)
print(
"default_operation on {} with args {} and kwargs {}".format(
elem.__class__.__name__, args, kwargs
)
)
@staticmethod
def custom_operation(elem, *args, **kwargs):
print(
"custom_operation on {} with args {} and kwargs {}".format(
elem.__class__.__name__, args, kwargs
)
)
@staticmethod
def another_custom_operation(elem, *args, **kwargs):
print(
"another_custom_operation on {} with args {} and kwargs {}".format(
elem.__class__.__name__, args, kwargs
)
)
def main():
elements = [ElementOne(), ElementTwo(), ElementThree(), ElementFour()]
visitor = Visitor()
for elem in elements:
visitor.visit(elem)
if __name__ == "__main__":
main()