php $this->render,PHP设计模式 - 装饰器模式

【一】模式定义

装饰器模式能够从一个对象的外部动态地给对象添加功能。

通常给对象添加功能,要么直接修改对象添加相应的功能,要么派生对应的子类来扩展,抑或是使用对象组合的方式。显然,直接修改对应的类这种方式并不可取。在面向对象的设计中,我们也应该尽量使用对象组合,而不是对象继承来扩展和复用功能。装饰器模式就是基于对象组合的方式,可以很灵活的给对象添加所需要的功能。装饰器模式的本质就是动态组合。动态是手段,组合才是目的。

常见的使用示例:Web服务层 —— 为 REST 服务提供 JSON 和 XML 装饰器。

【二】UML类图

df991e6540b37f9b6d62e307ec241a1f.png

【三】示例代码

RendererInterface.php

namespace DesignPatterns\Structural\Decorator;

/**

* RendererInterface接口

*/

interface RendererInterface

{

/**

* render data

*

* @return mixed

*/

public function renderData();

}

Webservice.php

namespace DesignPatterns\Structural\Decorator;

/**

* Webservice类

*/

class Webservice implements RendererInterface

{

/**

* @var mixed

*/

protected $data;

/**

* @param mixed $data

*/

public function __construct($data)

{

$this->data = $data;

}

/**

* @return string

*/

public function renderData()

{

return $this->data;

}

}

Decorator.php

namespace DesignPatterns\Structural\Decorator;

/**

* 装饰器必须实现 RendererInterface 接口, 这是装饰器模式的主要特点,

* 否则的话就不是装饰器而只是个包裹类

*/

/**

* Decorator类

*/

abstract class Decorator implements RendererInterface

{

/**

* @var RendererInterface

*/

protected $wrapped;

/**

* 必须类型声明装饰组件以便在子类中可以调用renderData()方法

*

* @param RendererInterface $wrappable

*/

public function __construct(RendererInterface $wrappable)

{

$this->wrapped = $wrappable;

}

}

RenderInXml.php

namespace DesignPatterns\Structural\Decorator;

/**

* RenderInXml类

*/

class RenderInXml extends Decorator

{

/**

* render data as XML

*

* @return mixed|string

*/

public function renderData()

{

$output = $this->wrapped->renderData();

// do some fancy conversion to xml from array ...

$doc = new \DOMDocument();

foreach ($output as $key => $val) {

$doc->appendChild($doc->createElement($key, $val));

}

return $doc->saveXML();

}

}

RenderInJson.php

namespace DesignPatterns\Structural\Decorator;

/**

* RenderInJson类

*/

class RenderInJson extends Decorator

{

/**

* render data as JSON

*

* @return mixed|string

*/

public function renderData()

{

$output = $this->wrapped->renderData();

return json_encode($output);

}

}

【四】测试代码

Tests/DecoratorTest.php

namespace DesignPatterns\Structural\Decorator\Tests;

use DesignPatterns\Structural\Decorator;

/**

* DecoratorTest 用于测试装饰器模式

*/

class DecoratorTest extends \PHPUnit_Framework_TestCase

{

protected $service;

protected function setUp()

{

$this->service = new Decorator\Webservice(array('foo' => 'bar'));

}

public function testJsonDecorator()

{

// Wrap service with a JSON decorator for renderers

$service = new Decorator\RenderInJson($this->service);

// Our Renderer will now output JSON instead of an array

$this->assertEquals('{"foo":"bar"}', $service->renderData());

}

public function testXmlDecorator()

{

// Wrap service with a XML decorator for renderers

$service = new Decorator\RenderInXml($this->service);

// Our Renderer will now output XML instead of an array

$xml = '<?xml  version="1.0"?>bar';

$this->assertXmlStringEqualsXmlString($xml, $service->renderData());

}

/**

* The first key-point of this pattern :

*/

public function testDecoratorMustImplementsRenderer()

{

$className = 'DesignPatterns\Structural\Decorator\Decorator';

$interfaceName = 'DesignPatterns\Structural\Decorator\RendererInterface';

$this->assertTrue(is_subclass_of($className, $interfaceName));

}

/**

* Second key-point of this pattern : the decorator is type-hinted

*

* @expectedException \PHPUnit_Framework_Error

*/

public function testDecoratorTypeHinted()

{

if (version_compare(PHP_VERSION, '7', '>=')) {

throw new \PHPUnit_Framework_Error('Skip test for PHP 7', 0, __FILE__, __LINE__);

}

$this->getMockForAbstractClass('DesignPatterns\Structural\Decorator\Decorator', array(new \stdClass()));

}

/**

* Second key-point of this pattern : the decorator is type-hinted

*

* @requires PHP 7

* @expectedException TypeError

*/

public function testDecoratorTypeHintedForPhp7()

{

$this->getMockForAbstractClass('DesignPatterns\Structural\Decorator\Decorator', array(new \stdClass()));

}

/**

* The decorator implements and wraps the same interface

*/

public function testDecoratorOnlyAcceptRenderer()

{

$mock = $this->getMock('DesignPatterns\Structural\Decorator\RendererInterface');

$dec = $this->getMockForAbstractClass('DesignPatterns\Structural\Decorator\Decorator', array($mock));

$this->assertNotNull($dec);

}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值