PHP Objects, Patterns and Practice (3rd edition)

(Barry) #1

CHAPTER 11 ■ PERFORMING AND REPRESENTING TASKS


operation now calls accept() on its children in turn, passing the visitor along. In this way, the
ArmyVisitor class visits every object in the tree.
With the addition of just a couple of methods, I have created a mechanism by which new
functionality can be plugged into my composite classes without compromising their interface and
without lots of duplicated traversal code.
On certain squares in the game, armies are subject to tax. The tax collector visits the army and levies
a fee for each unit it finds. Different units are taxable at different rates. Here’s where I can take advantage
of the specialized methods in the visitor class:


class TaxCollectionVisitor extends ArmyVisitor {
private $due=0;
private $report="";


function visit( Unit $node ) {
$this->levy( $node, 1 );
}


function visitArcher( Archer $node ) {
$this->levy( $node, 2 );
}


function visitCavalry( Cavalry $node ) {
$this->levy( $node, 3 );
}


function visitTroopCarrierUnit( TroopCarrierUnit $node ) {
$this->levy( $node, 5 );
}


private function levy( Unit $unit, $amount ) {
$this->report .= "Tax levied for ".get_class( $unit );
$this->report .= ": $amount\n";
$this->due += $amount;
}


function getReport() {
return $this->report;
}


function getTax() {
return $this->due;
}
}


In this simple example, I make no direct use of the Unit objects passed to the various visit methods.
I do, however, use the specialized nature of these methods, levying different fees according to the
specific type of the invoking Unit object.
Here’s some client code:


$main_army = new Army();
$main_army->addUnit( new Archer() );
$main_army->addUnit( new LaserCannonUnit() );
$main_army->addUnit( new Cavalry() );

Free download pdf