In the visitor mode on Python, I looked at the examples of other people on the Internet, and they are usually similar to the following code.
from abc import ABC, abstractmethod #Abstract Visitorclass AnimalVisitor(ABC): @abstractmethod def visit_dog(self, dog: "Dog"): pass @abstractmethod def visit_cat(self, cat: "Cat"): pass #Abstract animalsclass Animal(ABC): def __init__(self, name: str): = name @abstractmethod def accept(self, visitor: AnimalVisitor): pass # Specific animalsclass Dog(Animal): def accept(self, visitor): visitor.visit_dog(self) class Cat(Animal): def accept(self, visitor): visitor.visit_cat(self) # Specific visitors: Feed visitorsclass FeedingVisitor(AnimalVisitor): def visit_dog(self, dog): print(f"Give{}Feed dog food") def visit_cat(self, cat): print(f"Give{}Feed cat food") # Specific visitors: Check healthy visitorsclass HealthCheckVisitor(AnimalVisitor): def visit_dog(self, dog): print(f"examine{}Vaccination status") def visit_cat(self, cat): print(f"examine{}Do you need a bath")
Examples of use are as follows:
def main(): # Create an animal dog = Dog("Benefit") cat = Cat("Mimmy") # Create a visitor feeding_visitor = FeedingVisitor() health_visitor = HealthCheckVisitor() # Create an animal list animals = [dog, cat] # Perform different operations print("=== Feeding time ===") for animal in animals: (feeding_visitor) print("\n=== Health check ===") for animal in animals: (health_visitor) if __name__ == "__main__": main()
In the above-implemented visitor mode, the visitor's interface class (abstract class) generally accesses different visitors by defining different methods (methods with visit prefix). It's a bit strange, why not implement the visitor mode through method overloading?
Defining different methods to implement visitor patterns obviously violates some design principles. The visitor's interface class needs to be responsible for accessing different methods, and the correlation between these methods is not large (deleting a method has no effect on other methods), which obviously violates theSingle Responsibility Principle (SRP)
;If you want to add an animal (visitor), you need to modify the visitor interface class to add the corresponding method, which is contrary toOpening and closing principle (OCP)
The method of the visitor's interface class also depends on specific classes (for exampleDog
、Cat
class), this goes againstDependency Inversion Principle (DIP)
。
Using method overloading to implement the visitor pattern, there is no problem above, and the code is simpler and clearer. Python does not have traditional method overloading, butfunctools
There is a modulesingledispatchmethod
Single dispatch decorator, which can be borrowed here to implement "method overloading".
The code for using method overloading is as follows:
from abc import ABC, abstractmethod from functools import singledispatchmethod #Abstract Visitorclass AnimalVisitor(ABC): @abstractmethod def visit(self, animal: "Animal"): pass #Abstract animalsclass Animal(ABC): def __init__(self, name: str): = name def accept(self, visitor: AnimalVisitor): (self) # Specific animalsclass Dog(Animal): ... class Cat(Animal): ... # Specific visitors: Feed visitorsclass FeedingVisitor(AnimalVisitor): @singledispatchmethod def visit(self, animal: Animal): raise NotImplementedError(f"{type(animal)} Not reloaded visitmethod") @(Dog) def _(self, dog): print(f"Give{}Feed dog food") @(Cat) def _(self, cat): print(f"Give{}Feed cat food") # Specific visitors: Check healthy visitorsclass HealthCheckVisitor(AnimalVisitor): @singledispatchmethod def visit(self, animal: Animal): raise NotImplementedError(f"{type(animal)} Not reloaded visitmethod") @(Dog) def _(self, dog): print(f"examine{}Vaccination status") @(Cat) def _(self, cat): print(f"examine{}Do you need a bath")
You can see that this way visitors abstract classesAnimalVisitor
There is only one way to do it, that isvisit
。AnimalVisitor
Only one responsibility is to visit animals,Single responsibility principle
;When adding other animals, you do not need to modify the abstract class, which is in line withOpening and closing principle
;AnimalVisitor
Now only rely onAnimal
This abstract class is in line withReliance inversion principle
。
Some people may be worried that if the visitor abstract class does not list all the corresponding methods to access the animal class, it will lead to the specific visitor class missing some method overloading. This problem is considered in the above code,singledispatchmethod
Decoratedvisit
Use in the methodNotImplementedError
Defend exceptions if a specific animal is not overloadedvisit
method, an exception will be thrown.
This is the article about Python reloading the accessor mode. For more related content on Python visitor mode, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!