前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >php设计模式(十一):装饰器模式(Decorator)

php设计模式(十一):装饰器模式(Decorator)

作者头像
高久峰
发布2023-09-18 15:41:07
1530
发布2023-09-18 15:41:07
举报

装饰器模式

装饰器模式又称:装饰者模式、Wrappe、Decorator。装饰是一种结构型设计模式,允许你通过将对象放入包含行为的特殊封装对象中来为原对象绑定新的行为。

问题

装饰器模式就如生活中的装饰或者配料一样,一级一级包装。就拿长沙最火的 茶颜悦色 奶茶举例吧,茶颜悦色的奶茶有原味奶茶:幽兰拿铁(特色)、声声乌龙三季生椰 等,大部分奶茶都可以通过加价进行加料,加料类型有:奶油碧根果碎开心果碎 等,现实生活中我们可以买一杯奶茶进行多次加料,也可不加料,甚至可以把同一种料加三次,在软件开发中我们能很简单通过继承实现。

装饰模式是为已有的类动态添加更多功能,而且不改动原来的类基础上,使用 关联替代继承

解决方法

上述情况我们需要更改一个对象的行为时,第一个跳入脑海的想法就是扩展它所属的类。

但是,不能忽视继承可能引发的几个严重问题:

  1. 继承是静态的。 无法在运行时更改已有对象的行为, 只能 使用由不同子类创建的对象来替代当前的整个对象。
  2. 子类只能有一个父类。大部分编程语言不允许一个类同时继承多个类的行为。

前面我们介绍了 组合模式适配器模式 , 都是利用了设计原则中 组合优于继承的意识,在装饰器模式中也不例外。我们可以将包含多个指向其他对象的引用, 并将各种工作 委派给引用对象。

结构

MilkTea:原本的对象和装饰共同的接口 示例中指:奶茶

Oolong、Latte: 原本的对象 示例中指:声声乌龙、幽兰拿铁

Decorator: 实现接口的装饰抽象类

Cream、…:具体的装饰 示例中:奶油、碧根果、开心果

代码示例

奶茶基类

代码语言:javascript
复制
/**
 * 奶茶
 */
interface MilkTea
{
    /**
     * 名称
     * @return mixed
     */
    public function name();

    /**
     * 价格
     * @return mixed
     */
    public function price();
}

PHP

Copy

具体奶茶类

声声乌龙

代码语言:javascript
复制
/**
 * 声声乌龙
 */
class Oolong implements MilkTea
{
    public function name()
    {
        return '声声乌龙';
    }

    public function price()
    {
        return 16;
    }
}

PHP

Copy

幽兰拿铁

代码语言:javascript
复制
/**
 * 幽兰拿铁
 */
class Latte implements MilkTea
{
    public function name()
    {
        return '幽兰拿铁';
    }

    public function price()
    {
        return 17;
    }
}

PHP

Copy

加料类基类

代码语言:javascript
复制
class Decorator implements MilkTea
{
    protected $milkTea;

    public function __construct(MilkTea $milkTea)
    {
        $this->milkTea = $milkTea;
    }

    public function name()
    {
        if ($this->milkTea != null) {
            return $this->milkTea->name();
        }
        return '';
    }

    public function price()
    {
        if ($this->milkTea != null) {
            return $this->milkTea->price();
        }
        return 0;
    }
}

PHP

Copy

加料具体类

奶油

代码语言:javascript
复制
/**
 * 奶油
 */
class Cream extends Decorator
{
    public function name()
    {
        return $this->milkTea->name() . '+ 奶油';
    }

    public function price()
    {
        return $this->milkTea->price() + 4;
    }
}

PHP

Copy

碧根果

代码语言:javascript
复制
/**
 * 碧根果
 */
class Pecan extends Decorator
{
    public function name()
    {
        return $this->milkTea->name() . '+ 碧根果';
    }

    public function price()
    {
        return $this->milkTea->price() + 2;
    }
}

PHP

Copy

开心果

代码语言:javascript
复制
/**
 * 开心果
 */
class Pistachio extends Decorator
{
    public function name()
    {
        return $this->milkTea->name() . '+ 开心果';
    }

    public function price()
    {
        return $this->milkTea->price() + 4;
    }
}

PHP

Copy

客户端使用

代码语言:javascript
复制
/**
 * 我点一杯 幽兰拿铁+ 奶油+ 开心果
 */
$latte = new Latte();
$cream = new Cream($latte);
$pistachio = new Pistachio($cream);

echo $pistachio->name();
echo '   ' . $pistachio->price() . '元' . PHP_EOL;

/**
 * 点一杯加三个奶油的声声乌龙(因为我比较喜欢喝奶油)
 */

$oolong = new Oolong();
$cream = new Cream($oolong);
$cream = new Cream($cream);
$cream = new Cream($cream);

echo $cream->name();
echo '   ' . $cream->price() . '元' . PHP_EOL;

PHP

Copy

输出

代码语言:javascript
复制
幽兰拿铁+ 奶油+ 开心果   25元
声声乌龙+ 奶油+ 奶油+ 奶油   28元

UML

优缺点

优点

  • 无需创建新子类即可扩展对象的行为。
  • 可以在运行时添加或删除对象的功能。
  • 可以用多个装饰封装对象来组合几种行为。
  • 单一职责原则。可以将实现了许多不同行为的一个大类拆 分为多个较小的类。

缺点

  • 在封装器栈中删除特定封装器比较困难。
  • 实现行为不受装饰栈顺序影响的装饰比较困难。
  • 各层的初始化配置代码看上去可能会很糟糕。

总结

学过 建造者模式 的朋友可能会有疑问,这个怎么不直接用 建造者模式,其实 建造者模式 强调的是按照顺序稳定执行,而 装饰器模式 则可以自由灵活组合,比如像前面例子,我可以一杯奶茶点三个料。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 装饰器模式
  • 问题
  • 解决方法
  • 结构
  • 代码示例
    • 奶茶基类
      • 具体奶茶类
        • 加料类基类
          • 加料具体类
            • 客户端使用
            • UML
            • 优缺点
              • 优点
                • 缺点
                • 总结
                领券
                问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档