Фабричный метод не работает: вместо него возвращается родительский класс - PullRequest
0 голосов
/ 13 января 2012

Я пытаюсь реализовать то, что я считаю классом фабрики.У меня есть API-фреймворк.После того, как мой фронт-контроллер обработал запрос, он пытается вернуть вывод клиенту.Вызов в моем фронт-контроллере выглядит следующим образом:

<?php
...
$response_obj = new Response($response_str, 'json');
echo $response_obj->render();
?>

Мой Response класс в основном принимает второй аргумент в качестве типа класса для создания экземпляра и передает этому новому классу содержимое $response_str.Вот оно:

<?php
class Response {

    public function __construct($data, $format) {
        switch ($format) {
            case 'json':
                $obj = new ResponseJson($data);
            break;
        }
        return $obj;
    }
}

И тогда мой класс ResponseJson выглядит следующим образом:

<?php
class ResponseJson {

    protected $data;

    public function __construct($data) {
        $this->data = $data;
        return $this;
    }

    public function render() {
        header('Content-Type: application/json');
        return json_encode($this->data);
    }
}

Однако в моем фронт-контроллере $response_obj возвращает свой тип как Response ине ResponseJson, как ожидалось, и вызов метода render() (который существует в ResponseJson, а не Response) приводит к фатальной ошибке:

фатальная ошибка: вызов кнеопределенный метод Response :: render () в /Users/Martin/Sites/api-framework/index.php в строке 61

Где я ошибаюсь?

Ответы [ 3 ]

3 голосов
/ 13 января 2012

то, что вы описываете, не фабричный, а скорее неверный код.(__construct всегда будет возвращать новый экземпляр класса, в котором он реализован. На самом деле, ему не нужно ничего возвращать, потому что это не имеет никакого эффекта!)может вызываться без создания экземпляра объекта фабричного класса.Затем он создает экземпляр объекта класса (в большинстве случаев другой класс, как в вашем случае) и возвращает его.

ваш класс Response должен выглядеть следующим образом:

<?php
class Response {

    static public function create($data, $format) {
        switch ($format) {
            case 'json':
                $obj = new ResponseJson($data);
                break;
            case default:
                return NULL; // or throw exception!
                break;
        }
        return $obj;
    }
}

и ваш контроллер внешнего интерфейса, например:

<?php
...
$response_obj = Response::create($response_str, 'json');
echo $response_obj->render();
?>
1 голос
/ 13 января 2012

Если вы действительно хотите реализовать фабричный шаблон, вы можете сделать что-то вроде:

//Pseudo-code
class ResponseFactory
{
    createJSONResponse($data)
    {
        return new JSONResponse($data);
    }

    createXMLResponse($data)
    ...

    createDefaultResponse($data)
    {
        return createJSONResponse($data);
    }
}

Хотя, для типов ответов (которых, вероятно, будет только 2 или 3), я думаю, что я бы пошел со статическим фабричным методом Кая.

В ответ на ваш комментарий, почему я предпочитаю стандартную фабрику, каждый метод выглядит так, как указано выше, а не:

createResponse($type, $data)
{
    if ($type == 'json')
        return new JSONResponse($data);
    else if (...)
        ...
}

Тем более, что во многих случаях ваш абонент выглядит так:

$response = createResponse('json', $data);

Я предпочитаю это:

$response = createJSONResponse($data)

Хотя я должен отметить, что способность php вызывать строку как функцию может создать очень элегантную (хотя и небезопасную) абстрактную фабрику.

1 голос
/ 13 января 2012

Я думаю, вы неправильно поняли шаблон фабрики:

Метод конструктора вызывается автоматически при создании экземпляра класса как объекта, как я уверен, вы знаете.

создание экземпляра объекта всегда будет возвращать сам объект, оно не поддается большой логике для создания экземпляра объекта, который должен возвращать что-либо, кроме себя самого, особенно объект другого типа.Из-за этого правила метод конструктора не может возвращаться, он всегда будет вызываться только при создании экземпляра и, следовательно, возвращать сам объект.

Мне не совсем понятен ваш контекст, но кажется странным, что вы хотите фабрикув этом случае я бы ожидал, что ResponseJson будет расширять Response, а не создавать его.

Надеюсь, это поможет!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...