PHP设计模式(九)之装饰模式

作者: 温新

分类: 【设计模式】

阅读: 2562

时间: 2020-02-06 15:19:17

一、序言

装饰模式实际上是一直提倡的组合代替继承的实践方式,个人认为要理解装饰者模式首先需要理解为什么需要组合代替继承,继承又是为什么让人深恶痛绝.

为什么建议使用组合代替继承?

面向对象的特性有继承与封装,但两者却又有一点矛盾,继承意味子类依赖了父类中的实现,一旦父类中改变实现则会对子类造成影响,这是打破了封装性的一种表现. 而组合就是巧用封装性来实现继承功能的代码复用.

二、什么是装饰者模式

装饰者模式(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日

请登录后再评论