refactored Decorator pattern

This commit is contained in:
Dominik Liebler
2018-06-22 10:06:50 +02:00
parent 50cb2ea8d0
commit 4c0fbf4a7c
12 changed files with 107 additions and 103 deletions

View File

@@ -0,0 +1,10 @@
<?php
namespace DesignPatterns\Structural\Decorator;
interface Booking
{
public function calculatePrice(): int;
public function getDescription(): string;
}

View File

@@ -0,0 +1,16 @@
<?php
namespace DesignPatterns\Structural\Decorator;
abstract class BookingDecorator implements Booking
{
/**
* @var Booking
*/
protected $booking;
public function __construct(Booking $booking)
{
$this->booking = $booking;
}
}

View File

@@ -0,0 +1,16 @@
<?php
namespace DesignPatterns\Structural\Decorator;
class DoubleRoomBooking implements Booking
{
public function calculatePrice(): int
{
return 40;
}
public function getDescription(): string
{
return 'double room';
}
}

View File

@@ -0,0 +1,18 @@
<?php
namespace DesignPatterns\Structural\Decorator;
class ExtraBed extends BookingDecorator
{
private const PRICE = 30;
public function calculatePrice(): int
{
return $this->booking->calculatePrice() + self::PRICE;
}
public function getDescription(): string
{
return $this->booking->getDescription() . ' with extra bed';
}
}

View File

@@ -1,11 +0,0 @@
<?php
namespace DesignPatterns\Structural\Decorator;
class JsonRenderer extends RendererDecorator
{
public function renderData(): string
{
return json_encode($this->wrapped->renderData());
}
}

View File

@@ -25,33 +25,33 @@ Code
You can also find this code on `GitHub`_
RenderableInterface.php
Booking.php
.. literalinclude:: RenderableInterface.php
.. literalinclude:: Booking.php
:language: php
:linenos:
Webservice.php
BookingDecorator.php
.. literalinclude:: Webservice.php
.. literalinclude:: BookingDecorator.php
:language: php
:linenos:
RendererDecorator.php
DoubleRoomBooking.php
.. literalinclude:: RendererDecorator.php
.. literalinclude:: DoubleRoomBooking.php
:language: php
:linenos:
XmlRenderer.php
ExtraBed.php
.. literalinclude:: XmlRenderer.php
.. literalinclude:: ExtraBed.php
:language: php
:linenos:
JsonRenderer.php
WiFi.php
.. literalinclude:: JsonRenderer.php
.. literalinclude:: WiFi.php
:language: php
:linenos:

View File

@@ -1,8 +0,0 @@
<?php
namespace DesignPatterns\Structural\Decorator;
interface RenderableInterface
{
public function renderData(): string;
}

View File

@@ -1,24 +0,0 @@
<?php
namespace DesignPatterns\Structural\Decorator;
/**
* the Decorator MUST implement the RenderableInterface contract, this is the key-feature
* of this design pattern. If not, this is no longer a Decorator but just a dumb
* wrapper.
*/
abstract class RendererDecorator implements RenderableInterface
{
/**
* @var RenderableInterface
*/
protected $wrapped;
/**
* @param RenderableInterface $renderer
*/
public function __construct(RenderableInterface $renderer)
{
$this->wrapped = $renderer;
}
}

View File

@@ -2,32 +2,37 @@
namespace DesignPatterns\Structural\Decorator\Tests;
use DesignPatterns\Structural\Decorator;
use DesignPatterns\Structural\Decorator\DoubleRoomBooking;
use DesignPatterns\Structural\Decorator\ExtraBed;
use DesignPatterns\Structural\Decorator\WiFi;
use PHPUnit\Framework\TestCase;
class DecoratorTest extends TestCase
{
/**
* @var Decorator\Webservice
*/
private $service;
protected function setUp()
public function testCanCalculatePriceForBasicDoubleRoomBooking()
{
$this->service = new Decorator\Webservice('foobar');
$booking = new DoubleRoomBooking();
$this->assertEquals(40, $booking->calculatePrice());
$this->assertEquals('double room', $booking->getDescription());
}
public function testJsonDecorator()
public function testCanCalculatePriceForDoubleRoomBookingWithWiFi()
{
$service = new Decorator\JsonRenderer($this->service);
$booking = new DoubleRoomBooking();
$booking = new WiFi($booking);
$this->assertEquals('"foobar"', $service->renderData());
$this->assertEquals(42, $booking->calculatePrice());
$this->assertEquals('double room with wifi', $booking->getDescription());
}
public function testXmlDecorator()
public function testCanCalculatePriceForDoubleRoomBookingWithWiFiAndExtraBed()
{
$service = new Decorator\XmlRenderer($this->service);
$booking = new DoubleRoomBooking();
$booking = new WiFi($booking);
$booking = new ExtraBed($booking);
$this->assertXmlStringEqualsXmlString('<?xml version="1.0"?><content>foobar</content>', $service->renderData());
$this->assertEquals(72, $booking->calculatePrice());
$this->assertEquals('double room with wifi with extra bed', $booking->getDescription());
}
}

View File

@@ -1,21 +0,0 @@
<?php
namespace DesignPatterns\Structural\Decorator;
class Webservice implements RenderableInterface
{
/**
* @var string
*/
private $data;
public function __construct(string $data)
{
$this->data = $data;
}
public function renderData(): string
{
return $this->data;
}
}

View File

@@ -0,0 +1,18 @@
<?php
namespace DesignPatterns\Structural\Decorator;
class WiFi extends BookingDecorator
{
private const PRICE = 2;
public function calculatePrice(): int
{
return $this->booking->calculatePrice() + self::PRICE;
}
public function getDescription(): string
{
return $this->booking->getDescription() . ' with wifi';
}
}

View File

@@ -1,15 +0,0 @@
<?php
namespace DesignPatterns\Structural\Decorator;
class XmlRenderer extends RendererDecorator
{
public function renderData(): string
{
$doc = new \DOMDocument();
$data = $this->wrapped->renderData();
$doc->appendChild($doc->createElement('content', $data));
return $doc->saveXML();
}
}