装饰器模式是一种用于代替继承的技术,无需通过继承增加子类就能扩展对象的新功能。使用对象的关联关系代替继承关系,更加灵活,同时避免类型体系的快速膨胀。
如果对象开始要求启用过多的子类,那么相应的代码就会牺牲编程人员的理解力和可维护性。
示例:某个应用程序需要对音乐CD光盘进行处理,需要具备添加专辑和显示专辑列表的方法。客户要求应当采用多行并且每张专辑前面必须以序号为前缀的方式显示专辑列表。
代码如下:
<?php
class cdTrack
{
public $trackList;
public function __construct()
{
$this->trackList = array();
}
public function addTrack($track)
{
$this->trackList[] = $track;
}
public function getTrackList()
{
$output = '';
foreach ($this->trackList as $num=>$track)
{
$output .= ($num + 1).") {$track}".PHP_EOL;
}
return $output;
}
}
$myCD = new cdTrack();
foreach ($tracksFromExternalSource as $track) {
$myCD->addTrack($track);
}
echo $myCD->getTrackList();
#结果如下
1) What it means
2) Brr
3) Goodbye
对于上述示例,已经可以很好地解决客户需求了,但是,此时需求又发生了小变化,客户要求输出的内容都需要采用大写形式。
此刻最佳的做法并非是修改基类或创建父子关系,而是创建一个基于装饰器设计模式的对象。
代码如下:
<?php
require_once("cdTrack.php");
class cdTrackListDecoratorCaps
{
private $_cd;
public function __construct($cd)
{
$this->_cd = $cd;
}
public function makeCaps()
{
foreach ($this->_cd->trackList as &$track)
{
$track = strtoupper($track);
}
}
}
$tracksFromExternalSource = array('What it means', 'Brr', 'Goodbye');
$myCD = new cdTrack();
foreach ($tracksFromExternalSource as $track) {
$myCD->addTrack($track);
}
$myCDCaps = new cdTrackListDecoratorCaps($myCD);
$myCDCaps->makeCaps();
echo $myCD->getTrackList();
#结果如下
1) WHAT IT MEANS
2) BRR
3) GOODBYE
上述代码实现是通过引用已有的cdTrack对象,并实例化cdTrackListDecoratorCaps,然后就可以创建$myCDCaps变量,随后调用makeCaps方法实现所需的细微需求变化。
小结:
装饰模式降低系统的耦合度,可以动态的增加或删除对象的职责,并使得需要装饰的具体构建类和具体装饰类可以独立变化,以便增加新的具体构建类和具体装饰类。
优点:
扩展对象功能比继承灵活,不会导致类个数急剧增加
可以对一个对象进行多次装饰,创造出不同行为的组合,得到功能更加强大的对象
具体构建类和具体装饰类可以独立变化,用户可以根据需要自己增加新的具体构件子类和具体装饰子类
缺点:
产生很多小对象,大量小对象占据内存,一定程度上影响性能
装饰模式易于出错,调试排查比较麻烦
—————————————————————————————
PS:装饰模式和桥接模式的区别:
两个模式都是为了解决过多子类对象问题,但他们的诱因不一样。
桥接模式是对象自身现有机制沿着多个维度变化,是既有部分不稳定。
装饰模式是为了增加新的功能。
原创文章,作者:iConan,如若转载,请注明出处:https://www.aspyc.com/archives/683.html