2014-02-16 90 views
1

我有一個關於使用工廠動態創建類的問題。 假設我有一個核心命名空間,其中有一個框架的基類。除此之外,我還有一個應用程序特定文件的命名空間。現在我在core命名空間中有一個工廠,我將用它來創建一個驗證器類。現在有屬於框架的驗證器和專用於應用程序的驗證器。創建從不同命名空間創建類的工廠

除此之外,我有一個自動加載器將名稱空間解析到文件系統文件夾中。

例子:

負荷app\validators

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

負荷core\validators

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

最酷的事情是,如果工廠將首先嚐試加載從應用程序命名空間的類,如果不可能從核心命名空間。當然,我認爲實現工廠創建方法嘗試從app \ validators首先加載類,如果出現異常,然後嘗試從核心\驗證器加載它。但是,我將不得不從不同的工廠實現所有的創建方法,我想知道是否有一個很好的通用解決方案。

什麼使工廠在所需類的兩個名稱空間中查找的最佳方式是什麼? PS:我希望這個問題不是太愚蠢,因爲我對這種模式比較陌生。

+0

此外,當你進入命名空間的使用,你爲什麼會想退化爲通用名稱(無NS),還是希望應用程序名稱空間優先於核心框架?這會產生相當不可預測的結果。 – webmaster777

+0

我已經在沒有工廠的情況下實現了這種模式,其中應用程序類正在擴展核心類,並且核心中也總是有類的應用程序版本。在實際應用程序中創建類時,它將覆蓋核心版本 –

+0

可預測性是一個很好的觀點。現在當你說它的時候,當我不尊重它們時,定義命名空間似乎沒什麼意義...... – mightyplow

回答

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

在你的上下文中,我認爲它會更適合使用stat ic create(),但也許我錯了。

您還可以記錄create()方法的返回值,以便您的IDE(netbeans,eclipse,whatever)知道返回類型,並顯示建議(我想您的庫中有一個基本接口或抽象類,驗證):

/** 
* @return \core\validators\IValidator 
*/ 
public static function create($name) { 
    ... 
} 

編輯:

你可以使用這樣的事情,但你需要創建工廠的情況下,這是不是在我看來,最好的辦法,但在這裏你去:

Abstr行事基類,有一個具體的實施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"); 
+0

= D這幾乎就是我的自動加載器的樣子。解決辦法就是我的意思是不夠通用。當我爲其他類型的應用程序創建另一個工廠時,應該採用相同的方式,我將不得不再次實施相同的工作。但是,也許我可以像'驗證器'這樣的子名稱空間保存在一個屬性中,並使用它來不重複同樣的創建方法... – mightyplow

+1

我明白了,但我認爲,像這樣的事情是你可以做的最好的事情,如果你想使用這樣的工廠方法。你也可以在你的工廠類中創建一個包裝類,它知道它應該查找的名稱空間,然後遍歷它們,並嘗試加載它。 –

+0

這是個好主意。我想,我會試試這個。 – mightyplow

相關問題