【发布时间】:2017-08-04 23:57:17
【问题描述】:
让我们创建一个动物类型列表:
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;
}
现在我想在其他地方列出它们:
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);
现在我的问题是 Test 类与 Item 及其所有后代耦合。如果我这样重构整体:
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);
现在看起来更好一点,因为现在消除了 Test 和 Item 依赖项。还是因为isMammal()、isReptile()而闻起来很臭……这意味着每次产生新类型时,都应该更新Item。然而,基类知道其后代是一种不好的做法。优雅的方式是什么?
【问题讨论】:
-
您需要一些具有相同名称的方法,该方法在两个子类中都可用。像
makeChildren这样的东西。更严格地说,您可以创建一个接口makeChildren,并且两个类都应该实现它。 -
只需删除辅助方法...不是吗?在
Test::dump()中改用instanceof。最终源应该只知道它实际使用的类。您也可以考虑通过接口进行抽象。 -
如果你不喜欢使用类耦合,那么我相信只有接口是正确的方式。
-
因为您不需要使用精确的类。接口是一种抽象类型,需要按结构匹配,而不是精确的特定类。这意味着,无论你有多少类,它们都必须与你需要的动作兼容。它更灵活。许多框架核心组件都基于此功能构建,以提高可扩展性。
-
如果您通过
instanceof检查类 - 只有在变量包含确切的类实例的情况下才会给出true。如果您使用instanceof检查接口 - 它会将true提供给任何实现精确接口的类。可能有很多类可以使用一个接口。所以它最终允许更大的能力。
标签: php dependencies