lets create a list of animal types:
abstract class Item
{
public function run()
{
echo __FUNCTION__.'<br>';
}
}
class Reptile extends Item
{
public function putEgg()
{
echo __FUNCTION__.'<br>';
}
}
class Mammal extends Item
{
public function born()
{
echo __FUNCTION__.'<br>';
}
}
$list = [];
for ($i = 1; $i <= 10; $i++)
{
switch(mt_rand(1,2))
{
case 1 :
$o = new Reptile();
break;
case 2 :
$o = new Mammal();
break;
}
$list[] = $o;
}
now at somewhere else I would want to list them:
class Test
{
public function dump(array $list)
{
foreach ($list as $o)
{
/**
* @var Item $o
*/
echo '<hr>';
echo get_class($o).':<br>';
$o->run();
if ($o instanceof Mammal)
{
$o->born();
}
if ($o instanceof Reptile)
{
$o->putEgg();
}
}
}
}
(new Test())->dump($list);
now my problem is now Test
class is coupled to Item
and all of its descendants. If I refactor the whole like that:
abstract class Item
{
public function run()
{
echo __FUNCTION__.'<br>';
}
public function isReptile()
{
return $this instanceof Reptile;
}
public function isMammal()
{
return $this instanceof Mammal;
}
}
class Reptile extends Item
{
public function putEgg()
{
echo __FUNCTION__.'<br>';
}
}
class Mammal extends Item
{
public function born()
{
echo __FUNCTION__.'<br>';
}
}
$list = [];
for ($i = 1; $i <= 10; $i++)
{
switch(mt_rand(1,2))
{
case 1 :
$o = new Reptile();
break;
case 2 :
$o = new Mammal();
break;
}
$list[] = $o;
}
//
class Test
{
public function dump(array $list)
{
foreach ($list as $o)
{
/**
* @var Item $o
*/
echo '<hr>';
echo get_class($o).':<br>';
$o->run();
if ($o->isMammal())
{
$o->born();
}
if ($o->isReptile())
{
$o->putEgg();
}
}
}
}
(new Test())->dump($list);
a bit looks better since now Test
and Item
dependencies are eliminated. Still it smells because of isMammal()
, isReptile()
... it means every time a new type is born, Item should be updated. Nevertheless, its a bad practice that a base class know about its descendants. What is the elegant way?