PHP Objects, Patterns and Practice (3rd edition)

(Barry) #1

CHAPTER 10 ■ PATTERNS FOR FLEXIBLE OBJECT PROGRAMMING


Here, I have declared Tile and Plains classes as before but introduced a new class: TileDecorator.
This does not implement getWealthFactor(), so it must be declared abstract. I define a constructor that
requires a Tile object, which it stores in a property called $tile. I make this property protected so that
child classes can gain access to it. Now I’ll redefine the Pollution and Diamond classes:


class DiamondDecorator extends TileDecorator {
function getWealthFactor() {
return $this->tile->getWealthFactor()+2;
}
}


class PollutionDecorator extends TileDecorator {
function getWealthFactor() {
return $this->tile->getWealthFactor()-4;
}
}


Each of these classes extends TileDecorator. This means that they have a reference to a Tile object.
When getWealthFactor() is invoked, each of these classes invokes the same method on its Tile reference
before making its own adjustment.
By using composition and delegation like this, you make it easy to combine objects at runtime.
Because all the objects in the pattern extend Tile, the client does not need to know which combination
it is working with. It can be sure that a getWealthFactor() method is available for any Tile object,
whether it is decorating another behind the scenes or not.


$tile = new Plains();
print $tile->getWealthFactor(); // 2


Plains is a component. It simply returns 2

$tile = new DiamondDecorator( new Plains() );
print $tile->getWealthFactor(); // 4


DiamondDecorator has a reference to a Plains object. It invokes getWealthFactor() before adding its
own weighting of 2:


$tile = new PollutionDecorator(
new DiamondDecorator( new Plains() ));
print $tile->getWealthFactor(); // 0


PollutionDecorator has a reference to a DiamondDecorator object which has its own Tile reference.
You can see the class diagram for this example in Figure 10–5.
Free download pdf