使用您的代码示例更新答案
这是你的新工厂:
public static function factory(SimpleXMLElement $element)
{
$element->registerXPathNamespace("d", "http://www.w3.org/2005/Atom");
$category = $element->xpath("d:category[@scheme='http://schemas.google.com/g/2005#kind']");
$className = 'Model_Google_ '.$category[0]['label'];
if (class_exists($className)){
return new $className($element);
} else {
throw new Exception('Cannot handle '.$category[0]['label']);
}
}
我不确定我是否完全理解您的意思......为了重新表述这个问题,我理解“如何在不硬编码客户端代码中的选择的情况下创建正确的对象”
带自动加载
所以让我们从基本客户端代码开始
class BaseFactory
{
public function createForType($pInformations)
{
switch ($pInformations['TypeOrWhatsoEver']) {
case 'Type1': return $this->_createType1($pInformations);
case 'Type2': return $this->_createType2($pInformations);
default : throw new Exception('Cannot handle this !');
}
}
}
现在,让我们看看我们是否可以更改它以避免 if / switch 语句(并非总是必要的,但可以)
我们在这里将使用 PHP 自动加载功能。
首先,考虑自动加载已经到位,这是我们的新工厂
class BaseFactory
{
public function createForType($pInformations)
{
$handlerClassName = 'GoogleDocHandler'.$pInformations['TypeOrWhatsoEver'];
if (class_exists($handlerClassName)){
//class_exists will trigger the _autoload
$handler = new $handlerClassName();
if ($handler instanceof InterfaceForHandlers){
$handler->configure($pInformations);
return $handler;
} else {
throw new Exception('Handlers should implements InterfaceForHandlers');
}
} else {
throw new Exception('No Handlers for '.$pInformations['TypeOrWhatsoEver']);
}
}
}
现在我们必须添加自动加载功能
class BaseFactory
{
public static function autoload($className)
{
$path = self::BASEPATH.
$className.'.php';
if (file_exists($path){
include($path);
}
}
}
你只需要注册你的自动加载器
spl_autoload_register(array('BaseFactory', 'autoload'));
现在,每次您必须为类型编写新的处理程序时,它都会自动添加。
责任链
您可能不想在您的工厂中编写更“动态”的东西,并使用处理多个类型的子类。
例如
class BaseClass
{
public function handles($type);
}
class TypeAClass extends BaseClass
{
public function handles($type){
return $type === 'Type1';
}
}
//....
在 BaseFactory 代码中,您可以加载所有处理程序并执行类似的操作
class BaseFactory
{
public function create($pInformations)
{
$directories = new \RegexIterator(
new \RecursiveIteratorIterator(
new \RecursiveDirectoryIterator(self::BasePath)
), '/^.*\.php$/i'
);
foreach ($directories as $file){
require_once($fileName->getPathName());
$handler = $this->_createHandler($file);//gets the classname and create it
if ($handler->handles($pInformations['type'])){
return $handler;
}
}
throw new Exception('No Handlers for '.$pInformations['TypeOrWhatsoEver']);
}
}