Menu
本书未发布

装饰模式(Decorator)

2.5.1. 目的

为类实例动态增加新的方法。

2.5.2. 例子

  • Zend Framework: Zend_Form_Element 实例的装饰者
  • Web Service Layer: 用于 REST 服务的 JSON 和 XML 装饰者 (当然,在这个例子中理应只有一个是被允许的)

2.5.3. UML 图

file

2.5.4. Code

你也可以在 GitHub 上查看代码

RenderableInterface.php


<?php

namespace DesignPatterns\Structural\Decorator;

/**
* 创建渲染接口。
* 这里的装饰方法 renderData() 返回的是字符串格式数据。
*/
interface RenderableInterface
{
    public function renderData(): string;
}

Webservice.php


<?php

namespace DesignPatterns\Structural\Decorator;

/**
* 创建 Webservice 服务类实现 RenderableInterface。
* 该类将在后面为装饰者实现数据的输入。
*/
class Webservice implements RenderableInterface
{
    /**
    * @var string
    */
    private $data;

    /**
    * 传入字符串格式数据。
    */
    public function __construct(string $data)
    {
        $this->data = $data;
    }

    /**
    * 实现 RenderableInterface 渲染接口中的 renderData() 方法。
    * 返回传入的数据。
    */
    public function renderData(): string
    {
        return $this->data;
    }
}

RendererDecorator.php


<?php

namespace DesignPatterns\Structural\Decorator;

 /**
 * 装饰者必须实现渲染接口类 RenderableInterface 契约,这是该设计
 * 模式的关键点。否则,这将不是一个装饰者而只是一个自欺欺人的包
 * 装。
 * 
 * 创建抽象类 RendererDecorator (渲染器装饰者)实现渲染接口。
 */
abstract class RendererDecorator implements RenderableInterface
{
    /**
     * @var RenderableInterface
     * 定义渲染接口变量。
     */
    protected $wrapped;

    /**
     * @param RenderableInterface $renderer
     * 传入渲染接口类对象 $renderer。
     */
    public function __construct(RenderableInterface $renderer)
    {
        $this->wrapped = $renderer;
    }
}

XmlRenderer.php


<?php

namespace DesignPatterns\Structural\Decorator;

/**
* 创建 Xml 修饰者并继承抽象类 RendererDecorator 。
*/
class XmlRenderer extends RendererDecorator
{

    /**
    * 对传入的渲染接口对象进行处理,生成 DOM 数据文件。
    */
    public function renderData(): string
    {
        $doc = new \DOMDocument();
        $data = $this->wrapped->renderData();
        $doc->appendChild($doc->createElement('content', $data));

        return $doc->saveXML();
    }
}

JsonRenderer.php


<?php

namespace DesignPatterns\Structural\Decorator;

/**
* 创建 Json 修饰者并继承抽象类 RendererDecorator 。
*/
class JsonRenderer extends RendererDecorator
{
    /**
    * 对传入的渲染接口对象进行处理,生成 JSON 数据。
    */
    public function renderData(): string
    {
        return json_encode($this->wrapped->renderData());
    }
}

2.5.5. 测试

Tests/DecoratorTest.php


<?php

namespace DesignPatterns\Structural\Decorator\Tests;

use DesignPatterns\Structural\Decorator;
use PHPUnit\Framework\TestCase;

/**
* 创建自动化测试单元 DecoratorTest 。
*/
class DecoratorTest extends TestCase
{
    /**
     * @var Decorator\Webservice
     */
    private $service;

    /** 
    * 传入字符串 'foobar' 。
    */
    protected function setUp()
    {
        $this->service = new Decorator\Webservice('foobar');
    }

    /**
    * 测试 JSON 装饰者。
    * 这里的 assertEquals 是为了判断返回的结果是否符合预期。
    */
    public function testJsonDecorator()
    {
        $service = new Decorator\JsonRenderer($this->service);

        $this->assertEquals('"foobar"', $service->renderData());
    }

    /**
    * 测试 Xml 装饰者。
    */
    public function testXmlDecorator()
    {
        $service = new Decorator\XmlRenderer($this->service);

        $this->assertXmlStringEqualsXmlString('<?xml version="1.0"?><content>foobar</content>', $service->renderData());
    }
}

本文章首发在 Laravel China 社区
上一篇 下一篇
讨论数量: 0
发起讨论


暂无话题~
刻意练习,每日精进。
2
点赞
471
浏览
0
讨论
译者