コード例で回答を更新
これがあなたの新しい工場です:
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 Autoload 機能を使用します。
まず、自動ロードが行われていると考えてください。ここに新しい工場があります
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']);
}
}