工厂方法不起作用:返回父类

时间:2012-01-13 18:15:03

标签: php oop design-patterns

我正在尝试实施我认为的工厂类。我有一个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)会导致致命错误:

  

致命错误:在第61行的/Users/Martin/Sites/api-framework/index.php中调用未定义的方法Response :: render()

我哪里错了?

3 个答案:

答案 0 :(得分:3)

您所描述的不是工厂,而是无效的代码。 (__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 :(得分:1)

我认为你误解了工厂模式:

构造函数方法在类的实例化时作为对象自动调用,我相信你知道。

对象的实例化将始终返回对象本身,它违背了很多逻辑,以便对象的实例化返回除自身以外的任何东西,尤其是不同类型的对象。由于这个规则,构造函数方法不能返回,它将始终只在实例化时调用,从而返回对象本身。

我对你的背景并不完全清楚,但在这种情况下你想要一个工厂似乎很奇怪,我希望ResponseJson能够扩展Response而不是由它创建。

希望这有帮助!

答案 2 :(得分:1)

如果您确实想要实现工厂模式,可以执行以下操作:

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

    createXMLResponse($data)
    ...

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

虽然,对于响应类型(其中可能只有2或3个),我想我会选择Kaii的静态工厂方法。

在回复您的评论时,我更喜欢标准工厂的原因,每种方法都如上所述,而不是:

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

特别是因为在很多情况下你的来电者看起来像:

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

我更喜欢这个:

$response = createJSONResponse($data)

虽然我应该注意到php将字符串作为函数调用的能力可以使一个非常优雅(虽然有点不安全)的抽象工厂。