SpecialistOff.NET / Вопросы / Статьи / Фрагменты кода / Резюме / Метки / Помощь / Файлы
НазадМетки: python
Now consider applying a design pattern that has an entirely different goal to the trash sorting problem.
For this pattern, we are no longer concerned with optimizing the addition of new types of Trash to the system. Indeed, this pattern makes adding a new type of Trash more complicated. The assumption is that you have a primary class hierarchy that is fixed; perhaps it’s from another vendor and you can’t make changes to that hierarchy. However, you’d like to add new polymorphic methods to that hierarchy, which means that normally you’d have to add something to the base class interface. So the dilemma is that you need to add methods to the base class, but you can’t touch the base class. How do you get around this?
The design pattern that solves this kind of problem is called a “visitor” (the final one in the Design Patterns book), and it builds on the double dispatching scheme shown in the last section.
The visitor pattern allows you to extend the interface of the primary type by creating a separate class hierarchy of type Visitor to virtualize the operations performed upon the primary type. The objects of the primary type simply “accept” the visitor, then call the visitor’s dynamically-bound method. It looks like this:

Now, if v is a Visitable reference to an Aluminum object, the code:
PriceVisitor pv = PriceVisitor() v.accept(pv)
uses double dispatching to cause two polymorphic method calls: the first one to select Aluminum‘s version of accept( ), and the second one withinaccept( ) when the specific version of visit( ) is called dynamically using the base-class Visitor reference v.
This configuration means that new functionality can be added to the system in the form of new subclasses of Visitor. The Trash hierarchy doesn’t need to be touched. This is the prime benefit of the visitor pattern: you can add new polymorphic functionality to a class hierarchy without touching that hierarchy (once the accept( ) methods have been installed). Note that the benefit is helpful here but not exactly what we started out to accomplish, so at first blush you might decide that this isn’t the desired solution.
But look at one thing that’s been accomplished: the visitor solution avoids sorting from the master Trash sequence into individual typed sequences. Thus, you can leave everything in the single master sequence and simply pass through that sequence using the appropriate visitor to accomplish the goal. Although this behavior seems to be a side effect of visitor, it does give us what we want (avoiding RTTI).
The double dispatching in the visitor pattern takes care of determining both the type of Trash and the type of Visitor. In the following example, there are two implementations of Visitor: PriceVisitor to both determine and sum the price, and WeightVisitor to keep track of the weights.
You can see all of this implemented in the new, improved version of the recycling program.
As with DoubleDispatch.py, the Trash class is left alone and a new interface is created to add the accept( ) method:
# PatternRefactoring/trashvisitor/Visitable.py
# An class to add visitor functionality
# to the Trash hierarchy without
# modifying the base class.
class Visitable:
    # The method:
    def accept(self, Visitor v)
Since there’s nothing concrete in the Visitor base class, it can be created as an interface:
# PatternRefactoring/trashvisitor/Visitor.py
# The base class for visitors.
class Visitor:
    def visit(self, Aluminum a)
    def visit(self, Paper p)
    def visit(self, Glass g)
    def visit(self, Cardboard c)