我对使用工厂动态创建类有疑问。 假设我有一个框架基类所在的核心命名空间。除此之外,我还有应用程序特定文件的命名空间。现在我在cores命名空间中有一个工厂,我将用它来创建一个验证器类。现在有属于框架的验证器和特定于应用程序的验证器。
除此之外,我还有一个自动加载器,可以将命名空间解析为文件系统文件夹。
示例:
从app\validators
加载:
$passwordValidator = validatorFactory->create('PasswordValidator');
从core\validators
加载:
$emailValidator = validatorFactory->create('EmailValidator');
最酷的事情是,如果工厂首先尝试从app命名空间加载类,如果不可能从核心命名空间加载。当然我想到实现工厂创建方法来尝试首先从app \ validators加载类,如果出现异常,那么尝试从core \ validators加载它。但是后来我必须从不同的工厂实现所有的创建方法,我想知道是否有一个很好的通用解决方案。
使工厂查看所请求类的两个名称空间的最佳方法是什么?
PS:我希望这个问题不会太愚蠢,因为我对这些模式比较陌生。答案 0 :(得分:0)
您可以像这样重做自动加载功能,因此如果文件不存在,则可以检测到错误:
function __autoload($class) {
$parts = explode("\\", $class);
$path = implode(DIRECTORY_SEPARATOR, $parts) . ".php";
if (!file_exists($path)) {
throw new Exception("The class is not loadable");
} else {
include_once $path;
}
}
然后在工厂里:
class ValidatorFactory {
public static function create($name) {
try {
/*
* try to include from the core namespace
*/
$Class = "core\\validators\\" . $name;
$validator = new $Class();
return $validator;
} catch (Exception $ex) {
/*
* if it's not possible, try to include from the app namespace
* if the validator doesn't exist at all, then we
* let the user handle the error
*/
$Class = "app\\validators\\" . $name;
$validator = new $Class();
return $validator;
}
}
}
然后你可以像这样使用它:
$myValidator = ValidatorFactory::create("EmailValidator");
在你的上下文中,我认为使用静态create()
更合适,但也许我错了。
你还可以记录create()
方法的返回值,这样你的IDE(netbeans,eclipse,等等)就会知道返回类型,并显示建议(我想你的基本接口或抽象类都有)验证器库:
/**
* @return \core\validators\IValidator
*/
public static function create($name) {
...
}
编辑:
你可以使用这样的东西,但你需要创建工厂实例,这在我看来不是最好的主意,但是你走了:
抽象基类,具体实现为create()
abstract class AbstractFactory {
private $namespaces = array();
public function __construct($namespaces) {
$this->namespaces = $namespaces;
}
public function create($name) {
foreach ($this->namespaces as $namespace) {
$Class = $namespace . "\\" . $name;
try {
$instance = new $Class();
return $instance;
} catch (Exception $ex) {
// empty
}
}
throw new Exception("No class found");
}
}
实施
class ValidatorFactory extends AbstractFactory {
public function __construct() {
parent::__construct(array(
"app\\validators",
"core\\validators"
));
}
}
然后:
$factory = new ValidatorFactory();
$myValidator = $factory->create("MyValidator");