PHP Objects, Patterns and Practice (3rd edition)

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

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


The Army class has an addUnit() method that accepts a Unit object. Unit objects are stored in an
array property called $units. I calculate the combined strength of my army in the bombardStrength()
method. This simply iterates through the aggregated Unit objects, calling the bombardStrength() method
of each one.
This model is perfectly acceptable as long as the problem remains as simple as this. What happens,
though, if I were to add some new requirements? Let’s say that an army should be able to combine with
other armies. Each army should retain its own identity so that it can disentangle itself from the whole at
a later date. The ArchDuke’s brave forces may have common cause today with General Soames’ push
toward the exposed flank of the enemy, but a domestic rebellion may send his army scurrying home at
any time. For this reason, I can’t just decant the units from each army into a new force.
I could amend the Army class to accept Army objects as well as Unit objects:


function addArmy( Army $army ) {
array_push( $this->armies, $army );
}


Then I’d need to amend the bombardStrength() method to iterate through all armies as well as units:

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


foreach( $this->armies as $army ) {
$ret += $army->bombardStrength();
}


return $ret;
}


This additional complexity is not too problematic at the moment. Remember, though, dI woul need
to do something similar in methods like defensiveStrength(), movementRange(), and so on. My game is
going to be richly featured. Already the business group is calling for troop carriers that can hold up to ten
units to improve their movement range on certain terrains. Clearly, a troop carrier is similar to an army
in that it groups units. It also has its own characteristics. I could further amend the Army class to handle
TroopCarrier objects, but I know that there will be a need for still more unit groupings. It is clear that I
need a more flexible model.
Let’s look again at the model I have been building. All the classes I created shared the need for a
bombardStrength() method. In effect, a client does not need to distinguish between an army, a unit, or a
troop carrier. They are functionally identical. They need to move, attack, and defend. Those objects that
contain others need to provide methods for adding and removing. These similarities lead us to an
inevitable conclusion. Because container objects share an interface with the objects that they contain,
they are naturally suited to share a type family.

Free download pdf