装饰者模式

The decorator pattern can be used to extend (decorate) the functionality of a certain object statically, or in some cases at run-time, independently of other instances of the same class, provided some groundwork is done at design time. This is achieved by designing a new Decorator class that wraps the original class. This wrapping could be achieved by the following sequence of steps:

  1. Subclass the original Component class into a Decorator class (see UML diagram);
  2. In the Decorator class, add a Component pointer as a field;
  3. In the Decorator class, pass a Component to the Decorator constructor to initialize the Component pointer;
  4. In the Decorator class, forward all Component methods to the Component pointer;
  5. In the ConcreteDecorator class, override any Component method(s) whose behavior needs to be modified.

“装饰者模式”:在不改变原类和继承的前提下动态地扩展一个对象的功能;它是通过__包裹(Wrap)__方式来实现的,即创建一个包含_目标对象引用_的装饰器(函数或类),然后装饰器生成目标对象的_包裹对象_,该包裹对象就如目标对象的克隆体一样,它拥有和目标对象一样的接口(方法)但这些接口都是加强版的,最后返回包裹对象。

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
// PHP示例代码,来自网络

abstract class Component {
protected $data;
protected $value;
abstract public function getData();
abstract public function getValue();
}

class ConcreteComponent extends Component {
public function __construct() {
$this->value = 1000;
$this->data = "Concrete Component:\t{$this->value}\n";
}

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

public function getValue() {
return $this->value;
}
}

abstract class Decorator extends Component {}

class ConcreteDecorator1 extends Decorator { // 该类返回包裹对象
public function __construct(Component $data) { // Component $data就是目标对象的引用
$this->value = 500;
$this->data = $data;
}

// 加强版的接口
public function getData() {
return $this->data->getData() . "Concrete Decorator 1:\t{$this->value}\n";
}

public function getValue() {
return $this->value + $this->data->getValue();
}
}

class ConcreteDecorator2 extends Decorator {
public function __construct(Component $data) {
$this->value = 500;
$this->data = $data;
}

public function getData() {
return $this->data->getData() . "Concrete Decorator 2:\t{$this->value}\n";
}

public function getValue() {
return $this->value + $this->data->getValue();
}
}

class Client {
private $component;

public function __construct() {
$this->component = new ConcreteComponent();
$this->component = $this->wrapComponent($this->component);
echo $this->component->getData();
echo "Client:\t\t\t";
echo $this->component->getValue();
}

private function wrapComponent(Component $component) {
$component1 = new ConcreteDecorator1($component);
$component2 = new ConcreteDecorator2($component1);
return $component2;
}
}

$client = new Client();

// Result:
// Concrete Component: 1000
// Concrete Decorator 1: 500
// Concrete Decorator 2: 500
// Client: 2000