创建工厂,从不同的命名空间创建类

时间:2014-02-16 12:53:59

标签: php oop factory-pattern

我对使用工厂动态创建类有疑问。 假设我有一个框架基类所在的核心命名空间。除此之外,我还有应用程序特定文件的命名空间。现在我在cores命名空间中有一个工厂,我将用它来创建一个验证器类。现在有属于框架的验证器和特定于应用程序的验证器。

除此之外,我还有一个自动加载器,可以将命名空间解析为文件系统文件夹。

示例:

app\validators加载:

$passwordValidator = validatorFactory->create('PasswordValidator');

core\validators加载:

$emailValidator = validatorFactory->create('EmailValidator');

最酷的事情是,如果工厂首先尝试从app命名空间加载类,如果不可能从核心命名空间加载。当然我想到实现工厂创建方法来尝试首先从app \ validators加载类,如果出现异常,那么尝试从core \ validators加载它。但是后来我必须从不同的工厂实现所有的创建方法,我想知道是否有一个很好的通用解决方案。

使工厂查看所请求类的两个名称空间的最佳方法是什么?

PS:我希望这个问题不会太愚蠢,因为我对这些模式比较陌生。

1 个答案:

答案 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");