我正在忙于解析xml文档(google docs api)并将单个文档放入对象中.
有不同类型的文档(文档,电子表格,演示文稿).关于这些文件的大多数信息是相同的,但有些是不同的.
我们的想法是创建一个基础文档类,它保存所有共享信息,同时为每个特定文档类型使用子类.
问题是为不同类型创建正确的类.有两种方法可以区分文档的类型.每个条目都有一个category元素,我可以在其中找到类型.将使用的另一种方法是resourceId,格式为:id.
最天真的选择是创建一个if语句(或switch语句)来检查条目的类型,并为它创建相应的对象.但如果要添加新类型,则需要编辑代码.
现在我不确定是否有另一种解决方法,所以这就是我在这里问的原因.我可以在工厂方法中封装正确类型的对象的创建,因此所需的更改量是最小的.
现在,我有这样的事情:
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']");
if($category[0]['label'] == "spreadsheet")
{
return new Model_Google_Spreadsheet($element);
}
else
{
return new Model_Google_Base($element);
}
}
所以我的问题是,是否有其他方法我没有看到处理这种情况?
解决方法:
使用您的代码示例更新了答案
这是你的新工厂:
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语句(并非总是必要,但可以)
首先,考虑自动加载到位,这是我们的新工厂
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'));
现在,每次您必须为类型编写新的处理程序时,它将自动添加.
具有责任链
您可能不想在工厂中编写更“动态”的东西,并使用一个处理多个Type的子类.
例如
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']);
}
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。