简介
场景
通过继承和关联都可以给对象增加行为,区别如下:
- 继承是静态的(无法在程序运行时动态扩展),且作用于所有子类。硬编码,高耦合。
- 通过装饰器可以在运行时添加行为和属性到指定对象。关联关系就是在一个类中嵌入另一个类的对象,被嵌入的对象就是装饰器。可以动态决定是否调用这个内嵌对象,低耦合。
模式定义
装饰模式:动态地给指定对象增加额外职责。
装饰模式对客户透明,可以嵌套执行多次装饰,顺序不影响结果。
就增加对象功能来说,装饰模式(关联关系)比继承和实现这两种关系更为灵活。
模式特点
装饰模式包含 4 种角色:
- Component:抽象构件
- ConcreteComponent:具体构件
- Decorator:抽象装饰类
- ConcreteDecorator:具体装饰类
优缺点
优点:
- 装饰模式可以动态扩展一个对象的功能,可以在运行时通过配置文件选择不同的装饰器,从而实现不同的行为
- 装饰类可以排列组合,创造出很多不同行为的组合
- 装饰类扩展时,原有代码无须改变,符合“开闭原则”
缺点:
- 使用装饰模式进行系统设计时将产生很多小对象,每个对象仅负责一部分装饰任务
- 多次装饰的对象,调试时寻找错误可能需要逐级排查,较为烦琐
PHP 代码示例
下面例子中,通过不同的装饰器类对标题进行不同的操作:
<?php
class Book {
private $title;
private $author;
public function __construct($title, $author) {
$this->title = $title;
$this->author = $author;
}
public function getTitle() {
return $this->title;
}
}
class TitleDecorator {
protected $book;
protected $title;
public function __construct(Book $book) {
$this->book = $book;
$this->resetTitle();
}
public function resetTitle() {
$this->title = $this->book->getTitle();
}
public function showTitle() {
return $this->title;
}
}
class TitleStarDecorator extends TitleDecorator {
private $titleDecorator;
public function __construct(TitleDecorator $td) {
$this->titleDecorator = $td;
}
public function starTitle() {
$this->titleDecorator->title = str_replace(" ","*",$this->titleDecorator->title);
}
}
class TitleQuoteDecorator extends TitleDecorator {
private $titleDecorator;
public function __construct(TitleDecorator $td) {
$this->titleDecorator = $td;
}
public function quoteTitle() {
$this->titleDecorator->title = "《".$this->titleDecorator->title."》";
}
}
$book = new Book("a good world", "Lu Xun");
$td = new TitleDecorator($book);
$tsd = new TitleStarDecorator($td);
$tqd = new TitleQuoteDecorator($td);
function write_ln($str) {
echo $str.PHP_EOL.'<br/>';
}
write_ln($book->getTitle());
$tsd->starTitle();
write_ln($td->showTitle());
$tqd->quoteTitle();
write_ln($td->showTitle());
$tqd->quoteTitle();
write_ln($td->showTitle());
输出如下:
a good world
a*good*world
《a*good*world》
《《a*good*world》》