装饰器模式

定义

装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装。

这种模式创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。

主要角色

  • 抽象构件(Component)角色:定义一个对象接口,以规范准备接收附加职责的对象,从而可以给这些对象动态地添加职责。
  • 具体构件(Concrete Component)角色:定义一个将要接收附加职责的类。
  • 装饰(Decorator)角色:持有一个指向Component对象的指针,并定义一个与Component接口一致的接口。
  • 具体装饰(Concrete Decorator)角色:负责给构件对象增加附加的职责

适用性

  • 在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。
  • 处理那些可以撤消的职责,即需要动态的给一个对象添加功能并且这些功能是可以动态的撤消的。
  • 当不能生成子类的方法进行扩充时。一种情况是,可能有大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长。另一种情况可能是因为类定义被隐藏,或类定义不能用于生成子类。

一句话理解

不影响其他对象情况下,扩充某个具体类的操作

实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
<?php
/**
* Created by PhpStorm.
* User: Livfer
* Desc:
* Date: 2019/9/17
* Time: 15:34
*/

/**
* Interface RenderInterface
*/
interface RenderInterface
{
public function renderData();
}

class WebService implements RenderInterface
{
protected $data;

public function __construct($data)
{
$this->data = $data;
}

public function renderData()
{
return $this->data;
}
}

/**
* 装饰器 必须实现RenderInterface
* Class Decorator
*/
abstract class Decorator implements RenderInterface
{
protected $render;

public function __construct(RenderInterface $render)
{
$this->render = $render;
}

public function renderData()
{
return $this->render->renderData();
}
}

/**
* 具体装饰器
* Class XmlRender
*/
class XmlRender extends Decorator
{
public function renderData()
{
//原始数据
$originalData = parent::renderData();
//具体装饰器需要修改的操作
$doc = new DOMDocument();
foreach ($originalData as $key => $item) {
$doc->appendChild($doc->createElement($key,$item));
}
return $doc->saveXML();
}
}

/**
* 具体装饰器
* Class JsonRender
*/
class JsonRender extends Decorator
{

public function renderData()
{
// TODO: Implement renderData() method.
$originalData = parent::renderData();
return json_encode($originalData);
}
}

$webService = new WebService(['a'=>'foo','b'=>'bar']);
$xmlDecorator = new XmlRender($webService);
$data = $xmlDecorator->renderData();
echo "xml: ".$data;

$jsonDecorator = new JsonRender($webService);
$data = $jsonDecorator->renderData();
echo "json: ".$data;