2012-01-13 53 views
0

我试图实现我认为是工厂类的东西。我有一个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)会引发致命错误:

Fatal error: Call to undefined method Response::render() in /Users/Martin/Sites/api-framework/index.php on line 61

我哪里错了?

+0

@Kaii说什么。这里是一些关于PHP模式的简要介绍。第一个例子是一个工厂:http://php.net/manual/en/language.oop5.patterns.php – 2012-01-13 18:24:11

回答

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(); 
?> 
+0

谢谢,凯伊。非常感激! – 2012-01-13 18:27:57

+0

接受作为答案然后;) – Kaii 2012-01-13 18:31:21

+0

我不得不等待堆栈溢出让我接受,因为你回答如此之快! ;-) – 2012-01-13 18:37:59

1

我想你误会了工厂模式:

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

对象总是会返回对象本身的实例化,这违背了一个对象的实例返回任何东西自身以外,特别是不同类型的对象有很多逻辑的。由于这个规则,构造方法不能返回,它总是只会在实例化时被调用,并因此返回对象本身。

我不是你的背景完全清楚,但要在这种情况下一个工厂它似乎很奇怪,我希望ResponseJson延长不会被其创建的响应。

希望这会有所帮助!

+0

我猜“json”只是一个例子,“xml”将成为下一个逻辑实现。使用工厂是完全有道理的。可以说,web服务的使用者可以指定(例如,通过GET参数),以何种格式来获得答案。只要将这种偏好传递给面包,就完成了。 – Kaii 2012-01-13 18:34:00

+0

@凯伊钉了它。这个想法是使用一个通用的方法接口,而不是呈现响应 - 不管是格式 - 无论是JSON,XML还是其他。 – 2012-01-13 18:37:29

+0

+1提供为什么有__construct的解释()返回任何东西是我的答案是缺少 – Kaii 2012-01-13 18:38:27

1

如果你真的想实现一个工厂模式,你可以这样做:

//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的ca一个字符串作为一个函数可以使一个非常优雅(虽然有点不安全)的抽象工厂。

+0

无谓这不会是适合作为我则不得不调用像'createJSONResponse'的方法是不可取的。 – 2012-01-13 19:25:14

+0

您可以将其推广以产生一个抽象工厂模式,该模式将被称为createResponse('JSON',$ data)。两种模式都有优点,但我个人认为标准工厂更具可读性。如果您在运行时将响应类型添加到工厂,那么抽象工厂绝对是您的选择。 – Tim 2012-01-13 19:29:39