PHP Objects, Patterns and Practice (3rd edition)

(Barry) #1
CHAPTER 11 ■ PERFORMING AND REPRESENTING TASKS

$taxcollector = new TaxCollectionVisitor();
$main_army->accept( $taxcollector );
print "TOTAL: ";
print $taxcollector->getTax()."\n";


The TaxCollectionVisitor object is passed to the Army object’s accept() method as before. Once
again, Army passes a reference to itself to the visitArmy() method, before calling accept() on its children.
The components are blissfully unaware of the operations performed by their visitor. They simply
collaborate with its public interface, each one passing itself dutifully to the correct method for its type.
In addition to the methods defined in the ArmyVisitor class, TaxCollectionVisitor provides two
summary methods, getReport() and getTax(). Invoking these provides the data you might expect:


Tax levied for Army: 1
Tax levied for Archer: 2
Tax levied for LaserCannonUnit: 1
Tax levied for Cavalry: 3
TOTAL: 7


Figure 11–7 shows the participants in this example.

Figure 11–7. The Visitor pattern


Visitor Issues


The Visitor pattern, then, is another that combines simplicity and power. There are a few things to bear
in mind when deploying this pattern, however.
First, although it is perfectly suited to the Composite pattern, Visitor can, in fact, be used with any
collection of objects. So you might use it with a list of objects where each object stores a reference to its
siblings, for example.
By externalizing operations, you may risk compromising encapsulation. That is, you may need to
expose the guts of your visited objects in order to let visitors do anything useful with them. You saw, for
example, that for the first Visitor example, I was forced to provide an additional method in the Unit
interface in order to provide information for TextDumpArmyVisitor objects. You also saw this dilemma
previously in the Observer pattern.
Because iteration is separated from the operations that visitor objects perform, you must relinquish
a degree of control. For example, you cannot easily create a visit() method that does something both
before and after child nodes are iterated. One way around this would be to move responsibility for

Free download pdf