装饰器模式

什么是装饰器模式

给已有的对象增加装饰。在原有对象的基础上增加一些东西来创建一个新的对象,达到不改变原类文件以及不使用继承的情况下。
类图中包含一个隐含的 Client 类。
类图:
装饰器类图

为什么要使用装饰器模式

  • 装饰器模式与继承都能扩展原有对象的功能,但是装饰器模式更加灵活,开发者可以随心所欲的搭配装饰器。
  • 不用修改原类

此设计符合“四人帮”提出的开闭原则和优先使用对象组合而不是类继承原则。

什么时候使用装饰器模式

引用自百度百科:

  1. 需要扩展一个类的功能,或给一个类添加附加职责。
  2. 需要动态的给一个对象添加功能,这些功能可以再动态的撤销。
  3. 需要增加由一些基本功能的排列组合而产生的非常大量的功能,从而使继承关系变的不现实。
  4. 当不能采用生成子类的方法进行扩充时。一种情况是,可能有大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长。另一种情况可能是因为类定义被隐藏,或类定义不能用于生成子类。

怎么使用装饰器模式

  • 装饰器类需要实现被装饰者的接口,这样,客户端就会以为这是一个对象。
  • 装饰器需要引用被装饰对象。

show me your code

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
94
95
96
97
98
<?php

// 装饰器模式
interface Hero
{
public function equip();
}

/**
* 白起 -- 被装饰者
*/
class Zheng implements Hero
{
private $heroName = 'Zheng';

public $equipments;

public function equip()
{
$this->equipments = [];
}

public function showEquipments()
{
echo $this->heroName.' with ('.implode(',', $this->equipments).')';
}
}

/**
* 抽象装饰器
*/
abstract class Equipment implements Hero
{
public $hero;

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

public function equip() {}

public function showEquipments()
{
$this->hero->showEquipments();
}
}

/**
* 具体装饰器 - 鞋子
*/
class Shoes extends Equipment
{
public function __construct(Hero $hero)
{
parent::__construct($hero);
}

public function equip()
{
$this->hero->equipments[] = 'shoes';
}
}

/**
* 具体装饰器 - 盔甲
*/
class armour extends Equipment
{
public function __construct(Hero $hero)
{
parent::__construct($hero);
}

public function equip()
{
$this->hero->equipments[] = 'armour';
}
}

/**
* client
*/
class client
{
public function run()
{
$zheng = new Zheng();
$zhengWithShoes = new Shoes($zheng);
$zhengWithShoes->equip();
$zhengWithArmour = new armour($zheng);
$zhengWithArmour->equip();
$zhengWithArmour->showEquipments();
}
}

$client = new client();
$client->run();

输出结果:

1
Zheng with (shoes,armour)

参考文献

[B] Learning PHP设计模式
[L] 百度百科-装饰模式

[注]: B 代表书,L 代表网络链接