I had the opportunity to implement the Visitor pattern in my work, and I didn't understand it clearly, so this is a summary of what I learned from the following books.
The Visitor pattern can separate data structure and processing.
The Visitor pattern is divided into a class that holds data and a class that implements the algorithm (Visitor class).
If you have a data structure in your application and some algorithms access that data structure,
The Visitor pattern allows data structures to focus on retaining and accessing data.
You can extend the functionality without modifying the existing class. (Principle of open / closed)
Many elements are stored in the data structure, and I want to do some processing for each element.
Where should I write the "processing" code at this time? If you write it in a class that represents a data structure ** The data structure class must be modified each time new processing is needed. ** **
The Visitor pattern is useful for solving the above problems.
According to Introduction to Design Patterns Learned in Java Language, the following relationships are associated with data structure classes and algorithms that describe algorithms. there is.
Let the class that holds the data structure be the Visitable
class, and the class that describes the algorithm for the data structure be the Visitor
class.
Define the visit (visitable)
method in the Visitor
class.
In visit ()
, write the algorithm while accessing the attributes and behavior of the class of the data structure.
On the other hand, the Visitable
class defines the ʻaccept (visitor) method. Within ʻaccept (visitor)
, call visit ()
of the Visitor object passed as the ** argument. ** **
Describes a data structure class (Visitable class). Describes a class that holds list-type data and a class that holds dictionary-type data. Define a method (ʻaccept () `) that accepts the Visitor class in each class.
visitable.py
class VisitableList(list):
def accept(self, visitor):
visitor.visit_list(self)
class VisitableDict(dict):
def accept(self, visitor):
visitor.visit_dict(self)
Next, write the Visitor class that describes the algorithm. In the code below, the data held by the class of the data structure described above is simply output as standard.
visitor.py
class Printer(object):
def visit_list(self, instance):
print('The contents of the list: {}'.format(instance))
def visit_dict(self, instance):
print('Keys in the dictionary: {}'.format(
', '.join(instance.keys())
))
Then use the data structure class and the Visitor class as shown in the sample code below.
Create an object of the data structure class,
Data structure object .accept (Visitor object)
It is described as.
main.py
def main():
vistitable_list = VisitableList([1, 2, 3, 5])
vistitable_list.accept(Printer())
vistitable_dict = VisitableDict({'one': 1, 'two': 2, 'three': 3})
vistitable_dict.accept(Printer())
if __name__ == "__main__":
main()
$ python main.py
The contents of the list: [1, 2, 3, 5]
Keys in the dictionary: one, two, three
Introspection is the nature and coverage of an object (object in this case). A feature that can be investigated to cover what is possible.
For example, referencing or retrieving "what properties have" for an object is called introspection.
The following code takes advantage of the characteristics of introspection and describes a class that connects the Visitor and Visitor classes.
class Connect():
def __init__(self, visited, vistor):
self.__cls = visited.__class__.__name__
self.__method_name = 'visit_%s' % self.__cls
self.__method = getattr(vistor, self.__method_name, None)
# visit()Implemented
self.__method(visited)
vistied.__class.___name__
and getattr ()
are introspections.
In the code below, implement it using the Printer class described above as well.
main.py
if __name__ == "__main__":
Connect([1, 2, 3], Printer())
$ python main.py
The contents of the list: [1, 2, 3]
Keys in the dictionary: one, two, three
By using introspection, you don't have to implement accept () in your Visitable class.
In Introduction to Design Patterns Learned in Java Language, as a basic form,
Define ʻaccept ()in the data structure class and the
visit ()` method in the class that implements the algorithm.
Then, within the defined method, we call each other's methods. (A technique called double dispatch)
In Expert Python Programming Revised 2nd Edition, in Python, the attributes of objects are dynamically It turns out that you can refer to, and as a result you can implement the Visitor pattern without using the accept () method.
In any case, I think it is necessary to implement the visit () method in the definition class (Visitor
) after fully understanding the attributes and behavior of the class in the data structure.
Recommended Posts