PHP Objects, Patterns and Practice (3rd edition)

(Barry) #1
CHAPTER 10 ■ PATTERNS FOR FLEXIBLE OBJECT PROGRAMMING

function removeUnit( Unit $unit ) {


$this->units = array_udiff( $this->units, array( $unit ),


function( $a, $b ) { return ($a === $b)?0:1; } );


}


function bombardStrength() {
$ret = 0;
foreach( $this->units as $unit ) {
$ret += $unit->bombardStrength();
}
return $ret;
}
}


The addUnit() method checks that I have not yet added the same Unit object before storing it in the
private $units array property. removeUnit() uses a similar check to remove a given Unit object from the
property.


■Note I use an anonymous callback function in the removeUnit() method. This checks the array elements in


the $units property for equivalence. Anonymous functions were introduced in PHP 5.3. If you're running an older


version of PHP, you can use the create_function() method to get a similar effect:


$this->units = array_udiff( $this->units, array( $unit ),


create_function( '$a,$b', 'return ($a === $b)?0:1;' ) );


Army objects, then, can store Units of any kind, including other Army objects, or leaves such as Archer
or LaserCannonUnit. Because all units are guaranteed to support bombardStrength(), our
Army::bombardStrength() method simply iterates through all the child Unit objects stored in the $units
property, calling the same method on each.
One problematic aspect of the Composite pattern is the implementation of add and remove
functionality. The classic pattern places add() and remove() methods in the abstract super class. This
ensures that all classes in the pattern share a common interface. As you can see here, though, it also
means that leaf classes must provide an implementation:


class UnitException extends Exception {}


class Archer extends Unit {
function addUnit( Unit $unit ) {
throw new UnitException( get_class($this)." is a leaf" );
}


function removeUnit( Unit $unit ) {
throw new UnitException( get_class($this)." is a leaf" );
}

Free download pdf