PHP设计模式(九)之装饰模式
一、序言
装饰模式实际上是一直提倡的组合代替继承的实践方式,个人认为要理解装饰者模式首先需要理解为什么需要组合代替继承,继承又是为什么让人深恶痛绝.
为什么建议使用组合代替继承?
面向对象的特性有继承与封装,但两者却又有一点矛盾,继承意味子类依赖了父类中的实现,一旦父类中改变实现则会对子类造成影响,这是打破了封装性的一种表现. 而组合就是巧用封装性来实现继承功能的代码复用.
二、什么是装饰者模式
装饰者模式(Decorator Pattern):装饰模式指的是在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。
上面的解释来自于百度百科,有些不好理解,下来来看看简单的解释;
装饰者模式:动态地给一个对象添加一些额外的职责。
解释:举一个例子,我们要去买一个手抓饼,我们可以为自己要的手抓饼增加鸡蛋、火腿、里脊肉等其他食物,这些其他的食物就是用来修饰手抓饼的。我们可以为自己的手抓饼添加更多的辅助食物,如香肠、虾肉。
三、装饰器模式中的角色
**抽象构件(Component)角色:**给出一个抽象接口,已规范准备接收附加责任的对象。
**具体构件(ConcreteComponent)角色:**定义一个将要接收附加责任的类
**装饰(Decorator)角色:**持有一个构件(Component)对象的实例,并定义一个与抽象构件接口一致的接口。
**具体装饰(ConcreteDecorator)角色:**负责给构件对象“贴上”附加的责任。
解释:有了结构的了解,我们再来对上面的例子进行对应的解释:
抽象构件角色 相当于 手抓饼抽象角色(这里是告诉老板我要一个手抓饼)
具体构建角色 相当于 手抓饼实物(老板已经拿出手抓饼着手开始做了)
装饰角色 相当于 鸡蛋、火腿(老板让你看菜单,选什么其他食物)
具体装饰角色 相当于 老板已经为手抓饼上鸡蛋等你要的食物了。
四、装饰者模式使用场景
1)需要扩展一个类的功能为给一个类增加其他额外职责;
2)需要动态地给一个对象增加功能,这些功能还能动态撤销;
3)需要增加由一些基本功能的排列组合而产生的非常大量的功能
五、装饰者模式优缺点
优点:
1)装饰这模式和继承的目的都是扩展对象的功能,但装饰者模式比继承更灵活
2)通过使用不同的具体装饰类以及这些类的排列组合,设计师可以创造出很多不同行为的组合
3)装饰者模式有很好地可扩展性
缺点:
装饰者模式导致了设计中出现了许多的小对象,过度使用程序将变得更加复杂。
六、代码实现
BreadComponent.php
<?php
/**
* 抽象构件角色
*
* BreadComponent 抽象手抓饼构件角色
*/
interface BreadComponent
{
// 手抓饼
public function bread();
}
BreadConcreteComponent.php
<?php
/**
* 具体构件角色
*
* BreadConcreteComponent 手抓饼具体构件角色
*/
class BreadConcreteComponent implements BreadComponent
{
// 食物名称
private $foodName;
// 初始化食物名称
public function __construct(string $foodName)
{
$this->foodName = $foodName;
}
public function bread()
{
echo '客官你的 ' . $this->foodName . ' 还配上了 ';
}
}
Decorator.php
<?php
/**
* 装饰角色
*
* 其他食物抽象角色
*/
class Decorator implements BreadComponent
{
// 抽象构件角色对象实例对象
protected $component;
// 初始化抽象构件角色对象
public function __construct(BreadComponent $component)
{
$this->component = $component;
}
public function bread()
{
if(!empty($this->component)){
$this->component->bread();
}
}
}
Egg.php
<?php
/**
* 具体装饰角色
*
* Egg 鸡蛋具体角色
*/
class Egg extends Decorator
{
public function bread()
{
parent::bread();
echo '鸡蛋 +';
}
}
Ham.php
<?php
/**
* 具体装饰角色
*
* Ham 火腿具体角色
*/
class Ham extends Decorator
{
public function bread()
{
parent::bread();
echo ' 火腿';
}
}
index.php
<?php
require_once './BreadComponent.php';
require_once './BreadConcreteComponent.php';
require_once './Decorator.php';
require_once './Egg.php';
require_once './Ham.php';
// 创建手抓饼
$bread = new BreadConcreteComponent('手抓饼');
// 添加鸡蛋
$egg = new Egg($bread);
// 添加火腿
$ham = new Ham($egg);
// 送上做好的手抓饼
$ham->bread();
我是夕阳何处寻,期待和优秀的你一起同行!
夕阳何处寻
2020年2月6日