好习惯:使用接口
清单 7 显示了一个代码示例,在实现了加载用户的新方法后并没有进行更改。该示例显示了一个名为 PersonProvider 的接口,该接口将声明单个方法。如果任何代码使用 PersonProvider,代码都禁止直接使用实现类。相反,它就像是一个实际对象一样使用 PersonProvider。
清单 7. 使用接口的好习惯
<?php
interface PersonProvider
{
public function getPerson($givenName, $familyName);
}
class DBPersonProvider implements PersonProvider
{
public function getPerson($givenName, $familyName)
{
/* pretend to go to the database, get the person... */
$person = new Person();
$person->setPrefix("Mr.");
$person->setGivenName("John");
return $person;
}
}
class PersonProviderFactory
{
public static function createProvider($type)
{
if ($type == 'database')
{
return new DBPersonProvider();
} else {
return new NullProvider();
}
}
}
$config = 'database';
/* I need to get person data... */
$provider = PersonProviderFactory::createProvider($config);
$person = $provider->getPerson("John", "Doe");
echo($person->getPrefix());
echo($person->getGivenName());
?>
interface PersonProvider
{
public function getPerson($givenName, $familyName);
}
class DBPersonProvider implements PersonProvider
{
public function getPerson($givenName, $familyName)
{
/* pretend to go to the database, get the person... */
$person = new Person();
$person->setPrefix("Mr.");
$person->setGivenName("John");
return $person;
}
}
class PersonProviderFactory
{
public static function createProvider($type)
{
if ($type == 'database')
{
return new DBPersonProvider();
} else {
return new NullProvider();
}
}
}
$config = 'database';
/* I need to get person data... */
$provider = PersonProviderFactory::createProvider($config);
$person = $provider->getPerson("John", "Doe");
echo($person->getPrefix());
echo($person->getGivenName());
?>
在使用接口时,尝试避免直接引用实现类。相反,使用对象外部的内容可以提供正确的实现。如果您的类将装入基于某些逻辑的实现,它仍然需要获取所有实现类的定义,并且那样做也无法取得任何效果。
您可以使用 Factory 模式来创建实现接口的实现类的实例。根据约定,factory 方法将以 create 为开头并返回接口。它可以为您的 factory 获取必要的参数以计算出应当返回哪个实现类。
在清单 7 中,createProvider() 方法只是获取 $type。如果 $type 被设为 database,工厂将返回 DBPersonProvider 的实例。从数据库中装入人员的任何新实现都不要求在使用工厂和接口的类中进行任何更改。DBPersonProvider 将实现 PersonProvider 接口并且拥有 getPerson() 方法的实际实现。