Наследование, конструктор для неизвестного класса потомка.

Rammstein

PHPClub::News
Наследование, конструктор для неизвестного класса потомка.

Существует несколько классов объектов, объединённых одним интерфейсом, но с разной реализацией. Нужно создавать экземпляр по ID, но не известно в какому из классов он будет принадлежать. Какой патерн следует использовать?

В общей сложности требуется, чтобы для разработчика не имело значения, новость это или статья, работа идёт одинаково:
1) Инициализация по ID (уникальный среди всех классов), это место меня и интересует
2) Использование унифицированного интерфейса с, возможно, разной реализацией.

-~{}~ 29.04.06 13:02:

Забыл важную деталь, объект должен иметься в единственном количестве. Т.е. на один ID приходится один экземпляр.
 

vadim

Guest
здесь конструктор не поможет, так как каждый конструктор принадлежит определённому классу. Можно сделать статическую функцию, которая будет по какому то параметру создавать объект и возвращать его обратно. Есть какой то параметр, по которому можно точно сказать, что это за тип??
 

Rammstein

PHPClub::News
Да, есть, но выясняется он только после выборки из БД. Видно нужно копать в сторону Factory
 

vadim

Guest
Rammstein
Так это оно и есть.
Всё равно нужно знать, объект какого класса возвращать.
А это можно узнать только по какому то параметру.
Factory по сути - это обычный switch, который в зависимости от параметра возвращает класс.
У меня же например, название класса генерируется автоматически из параметра в Базе данных, то есть switch-а нет
 

Rammstein

PHPClub::News
Да, именно "название класса генерируется автоматически из параметра в Базе данных" и нужно.
 

vadim

Guest
У меня чтото типа этого(код на работе, поэтому точно не помню)

function get_object($type)
{
$className="CONTENT_".$type;
$object=new $className();
return $object
}

$type берётся из базы
 

zerkms

TDD infected
Команда форума
PHP:
function factory($id) {
    static $instances;
    
    $list = array(
        0 => 'news',
        1 => 'article',
        2 => 'foo',
        );
    
    if (isset($list[$id])) {
        if (!isset($instances[$id])) {
            $instances[$id] = new $list[$id]();
        }
        return $instances[$id];
    }
    
    return null;
}

factory(1);
аццкий код ;)
 

Rammstein

PHPClub::News
Писал уже в час ночи. Спать хотелось :)

Итак, задача была изначально такая:
Вложенными множествами хранится структура дерева. Каждый узел загружается в php-объект, но класс объекта (а значит и реализация методов типа "ПолучитьВсехПотомков()") не известен. Требуется же загружать этот узел по ID. Т.е. завернуть в конструктор одного класса не представляется возможным.
В результате, были созданы несколько методов типа getDirectory*, например:
PHP:
    /**
     * Инициализирует объект директории по массиву данных
     *
     * @param array $data
     * @return VFSDirectory
     */
    function getDirectoryByArray(array $data)
    {
        $class = $data['class'];
        $class_file = "VFS/Directories/$class.php";
        if(!file_exists($class_file)) throw new ExeptionDirectoryClassDoesNotExists();
        require_once($class_file);
        $dir = new $class($data['node_id'], false);
        $dir->loadFromArray($data);
        $dir->setOptions(unserialize($data['options']));
        return $dir;
    }
Как видно, у объекта узла ( $dir ) присутствует метод loadFromArray($data);, который входит в группу методов loadFrom*. Опять же реализация:
PHP:
/**
     * Загружает данные о директории из массива
     *
     * @param array $array
     */
    function loadFromArray(array $array)
    {
        if(isset($array['node_id']) AND $array['node_id'] != $this->node_id)
        {
            throw new Exception("Неверный массив. Инициализировался объект с id {$this->node_id}, а не {$array['node_id']}");
        }
        $this->node_left = $array['node_left'];
        $this->node_right = $array['node_right'];
        $this->node_level = $array['node_level'];
        $this->main_obj = $array['main_obj'];
        $this->name = $array['name'];
    }
А используется это всё так (из объекта узла, а точнее из стандартного его варианта):
PHP:
/**
     * Возвращает родительскую директорию. Если это и так самая верхняя
     * директория (корень), то возвращает $this
     * 
     * @return VFSDirectory
     */
    function getParent()
    {
        if($this->isRoot()) return $this;
        $sql = "SELECT * FROM {$this->getTblPrefix()}directories 
                            WHERE node_left < '{$this->node_left}' AND node_right > '{$this->node_left}'
                            ORDER BY node_left DESC LIMIT 1";
        $res = $this->getDb()->query($sql);
        $res = $res->fetch();
        return VFS::getInstance()->getDirectoryByArray($res);
    }
Вобщем, использовал фактори метод.
Может что лучше можно придумать?

itprog
Пишу VFS :)

-~{}~ 30.04.06 11:51:

P.S> При желании можно будет прикрутить анти-размножатель объектов одного узла в getDirectory* методах, простым хранением и проверкой наличия экземпляров в хранилище.
 

Sherman

Mephi
а у вас каждый узел это прототип объекта или же его реальный экземпляр?

т.е. я имею ввиду что:

Код:
node_type_parent
  node_type_child
иерархия дает нам некоторую информацию о типах объекта, например о том, что объект типа node_type_child является дочерним по отношению к node_type_parent и наследует часть его свойств.

но сами же объекты, а точнее их реальные экземпляры хранятся где-то еще

или

иерархия — это и есть реальные объекты определенных типов?
 
Сверху