Skip to content

Commit 3a2fdfe

Browse files
committed
Decorator Design Pattern
1 parent 7b2113b commit 3a2fdfe

File tree

9 files changed

+230
-0
lines changed

9 files changed

+230
-0
lines changed
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?php
2+
3+
namespace PhpDesignPatterns\Structural\Decorator;
4+
5+
/**
6+
* Class ApiResponse
7+
* @package PhpDesignPatterns\Structural\Decorator
8+
*/
9+
class ApiResponse implements ResponseInterface
10+
{
11+
/**
12+
* Render the api response.
13+
*
14+
* @return mixed
15+
*/
16+
public function render()
17+
{
18+
return array(
19+
'status' => 'ok',
20+
'message' => 'raw api response',
21+
);
22+
}
23+
}

Structural/Decorator/Decorator.php

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?php
2+
3+
namespace PhpDesignPatterns\Structural\Decorator;
4+
5+
/**
6+
* Abstract class Decorator
7+
*
8+
* Provides basic methods for Concrete Decorators.
9+
*
10+
* @package PhpDesignPatterns\Structural\Decorator
11+
*/
12+
abstract class Decorator implements ResponseInterface
13+
{
14+
/**
15+
* Instance of ResponseInterface.
16+
*
17+
* @var ResponseInterface
18+
*/
19+
protected $wrapper;
20+
21+
/**
22+
*
23+
* @param ResponseInterface $response The object we need to extend responsabilities to.
24+
*/
25+
public function __construct(ResponseInterface $response)
26+
{
27+
$this->wrapper = $response;
28+
}
29+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?php
2+
3+
namespace PhpDesignPatterns\Structural\Decorator;
4+
5+
/**
6+
* Class JsonResponse
7+
* @package PhpDesignPatterns\Structural\Decorator
8+
*/
9+
class JsonResponse extends Decorator
10+
{
11+
/**
12+
* Transform output to json.
13+
*
14+
* @return string
15+
*/
16+
public function render()
17+
{
18+
$output = $this->wrapper->render();
19+
return json_encode($output);
20+
}
21+
}

Structural/Decorator/README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# Decorator Design Pattern
2+
3+
### Intent
4+
5+
“Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality.”
6+
7+
Excerpt From: Erich Gamma. “Design Patterns: Elements of Reusable Object-Oriented Software.”
8+
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?php
2+
3+
namespace PhpDesignPatterns\Structural\Decorator;
4+
5+
/**
6+
* Interface ResponseInterface
7+
* @package PhpDesignPatterns\Structural\Decorator
8+
*/
9+
interface ResponseInterface
10+
{
11+
/**
12+
* Return rendered output.
13+
*
14+
* @return mixed
15+
*/
16+
public function render();
17+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?php
2+
3+
namespace PhpDesignPatterns\Structural\Decorator;
4+
5+
/**
6+
* Class XmlResponse
7+
* @package PhpDesignPatterns\Structural\Decorator
8+
*/
9+
class XmlResponse extends Decorator
10+
{
11+
/**
12+
* Transform output to json.
13+
*
14+
* @return string
15+
*/
16+
public function render()
17+
{
18+
$output = $this->wrapper->render();
19+
$xml = new \SimpleXMLElement("<root />");
20+
foreach($output as $row_key => $row_value) {
21+
$xml->addChild($row_key, $row_value);
22+
}
23+
return $xml->asXml();
24+
}
25+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?php
2+
3+
namespace PhpDesignPatterns\Tests\Structural\Decorator;
4+
5+
use PhpDesignPatterns\Structural\Decorator\ApiResponse;
6+
7+
/**
8+
* Class ApiResponseTest
9+
* @package Tests\Structural\Decorator
10+
*/
11+
class ApiResponseTest extends \PHPUnit_Framework_TestCase
12+
{
13+
/**
14+
* Instance needed for testing.
15+
*
16+
* @var ApiResponse
17+
*/
18+
private $api_response;
19+
20+
/**
21+
* Testing render.
22+
*/
23+
public function testRender()
24+
{
25+
$expected = array(
26+
'status' => 'ok',
27+
'message' => 'raw api response',
28+
);
29+
$this->api_response = new ApiResponse();
30+
$this->assertEquals($expected, $this->api_response->render(), 'The result is not the expected one.');
31+
}
32+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?php
2+
3+
namespace PhpDesignPatterns\Tests\Structural\Decorator;
4+
5+
use PhpDesignPatterns\Structural\Decorator\JsonResponse;
6+
7+
/**
8+
* Class JsonResponseTest
9+
* @package PhpDesignPatterns\Tests\Structural\Decorator
10+
*/
11+
class JsonResponseTest extends \PHPUnit_Framework_TestCase
12+
{
13+
/**
14+
* Test instance.
15+
*
16+
* @var JsonResponse
17+
*/
18+
private $json_render;
19+
20+
/**
21+
* Testing decorated render.
22+
*/
23+
public function testRender()
24+
{
25+
$fake_render = array('message' => 'api response to json');
26+
$api_mock = $this->getMock('PhpDesignPatterns\\Structural\\Decorator\\ResponseInterface', array('render'));
27+
$api_mock
28+
->expects($this->once())
29+
->method('render')
30+
->will($this->returnValue($fake_render))
31+
;
32+
$this->json_render = new JsonResponse($api_mock);
33+
$expected = '{"message":"api response to json"}';
34+
$this->assertEquals($expected, $this->json_render->render());
35+
}
36+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<?php
2+
3+
namespace PhpDesignPatterns\Tests\Structural\Decorator;
4+
5+
use PhpDesignPatterns\Structural\Decorator\XmlResponse;
6+
7+
/**
8+
* Class XmlResponseTest
9+
* @package PhpDesignPatterns\Tests\Structural\Decorator
10+
*/
11+
class XmlResponseTest extends \PHPUnit_Framework_TestCase
12+
{
13+
/**
14+
* Test instance.
15+
*
16+
* @var XmlResponse
17+
*/
18+
private $xml_render;
19+
20+
/**
21+
* Testing decorated render.
22+
*/
23+
public function testRender()
24+
{
25+
$fake_render = array('message' => 'api response to xml');
26+
$api_mock = $this->getMock('PhpDesignPatterns\\Structural\\Decorator\\ResponseInterface', array('render'));
27+
$api_mock
28+
->expects($this->once())
29+
->method('render')
30+
->will($this->returnValue($fake_render))
31+
;
32+
$this->xml_render = new XmlResponse($api_mock);
33+
$expected = <<<XML
34+
<?xml version="1.0"?>
35+
<root><message>api response to xml</message></root>\n
36+
XML;
37+
$this->assertEquals($expected, $this->xml_render->render());
38+
}
39+
}

0 commit comments

Comments
 (0)