abstract
class
Unit {
abstract
function
bombardStrength();
function
accept(ArmyVisitor
$visitor
){
$method
=
"visit"
. get_class(
$this
);
$visitor
->
$method
(
$this
);
}
protected
function
setDepth(
$depth
){
$this
->depth =
$depth
;
}
function
getDepth(){
return
$this
->depth;
}
}
class
Archer
extends
Unit{
function
bombardStrength(){
return
4;
}
}
class
LaserCannonUnit
extends
Unit{
function
bombardStrength(){
return
44;
}
}
class
Cavalry
extends
Unit{
function
bombardStrength(){
return
2;
}
}
abstract
class
CompositeUnit
extends
Unit{
private
$units
=
array
();
function
getComposite(){
return
$this
;
}
protected
function
units(){
return
$this
->units;
}
function
removeUnit(Unit
$unit
){
$this
->units =
array_udiff
(
$this
->units,
array
(
$unit
),
function
(
$a
,
$b
){
return
(
$a
===
$b
)?0:1;}
);
}
function
addUnit(Unit
$unit
){
if
(in_array(
$unit
,
$this
->units,true)){
return
;
}
$unit
->setDepth(
$this
->depth + 1);
$this
->units[] =
$unit
;
}
function
bombardStrength(){
$ret
= 0;
foreach
(
$this
->units
as
$unit
){
$ret
+=
$unit
->bombardStrength();
}
return
$ret
;
}
function
accept(Armyvisitor
$visitor
){
parent::accept(
$visitor
);
foreach
(
$this
->units
as
$thisunit
){
$thisunit
->accept(
$visitor
);
}
}
}
class
Army
extends
CompositeUnit {
}
class
TroopCarrier
extends
CompositeUnit {
}
abstract
class
ArmyVisitor{
abstract
function
visit(Unit
$node
);
function
visitArcher(Archer
$node
){
$this
->visit(
$node
);
}
function
visitCavalry(Cavalry
$node
){
$this
->visit(
$node
);
}
function
visitLaserCannonUnit(LaserCannonUnit
$node
){
$this
->visit(
$node
);
}
function
visitTroopCarrierUnit(Cavalry
$node
){
$this
->visit(
$node
);
}
function
visitArmy(Cavalry
$node
){
$this
->visit(
$node
);
}
}
class
TextDumpArmyVisitor
extends
ArmyVisitor {
private
$text
=
""
;
function
visit(Unit
$node
){
$ret
=
""
;
$pad
= 4 *
$node
->getDpth();
$ret
.= sprintf(
"%{$pad}s"
,
""
);
$ret
.=get_class(
$node
).
": "
;
$ret
.=
"bombard: "
.
$node
->bombardStrength() .
"\n"
;
$this
->text .=
$ret
;
}
function
getText
(){
return
$this
->text;
}
}
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;
}
}
class
UnitScript {
static
function
joinExisting(Unit
$newUnit
,Unit
$occupyingUnit
){
$comp
;
if
(!
is_null
(
$com
=
$occupyingUnit
->getComposite())){
$comp
->addUnit(
$newUnit
);
}
else
{
$comp
=
new
Army();
$comp
->addUnit(
$occupyingUnit
);
$com
->addUnit(
$newUnit
);
}
return
$comp
;
}
}
$main_army
=
new
Army();
UnitScript::joinExisting(
new
Archer(),
$main_army
);
UnitScript::joinExisting(
new
LaserCannonUnit(),
$main_army
);
UnitScript::joinExisting(
new
Cavalry(),
$main_army
);
$textdump
=
new
TextDumpArmyVisitor();
$main_army
->accept(
$textdump
);
print
$textdump
->
getText
();
$main_army
=
new
Army();
UnitScript::joinExisting(
new
Archer(),
$main_army
);
UnitScript::joinExisting(
new
LaserCannonUnit(),
$main_army
);
UnitScript::joinExisting(
new
Cavalry(),
$main_army
);
$taxcollector
=
new
TaxCollectionVisitor();
$main_army
->accept(
$taxcollector
);
print
$taxcollector
->getTax();