PHP设计模式(七)-装饰器模式


layout: post
title: "PHP设计模式(七)-装饰器模式"
date: 2016-06-07 10:53:23 +0800
comments: true
categories: [php]


1、模式定义

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

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

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

2、UML类图

PHP设计模式(七)-装饰器模式_第1张图片
image

3、实例代码

定义接口:

    
    data = $data;
        }
    
        /**
         * @return string
         */
        public function renderData()
        {
            return $this->data;
        }
    }

个人感觉在这里没有必要实现RendererInterface接口,
实现这个接口过后就必须实现renderData方法,而这个方法仅仅是用来返回数据。
但是这个名字和后面装饰器的实现方法重名,很容易混乱。
这里如果不实现RendererInterface接口,将renderData()改为getData()应该会好一些,至少程序没那么容易搞混。

装饰器抽象类:

    wrapped = $wrappable;
        }
    }
    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();
        }
    }
    wrapped->renderData();
    
            return json_encode($output);
        }
    }

4、测试代码

    service = new Decorator\Webservice(array('foo' => 'bar'));//实例化 Webservice 类
        }
    
        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 = '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);
        }
    } 

你可能感兴趣的:(PHP设计模式(七)-装饰器模式)