PHP设计模式之装饰器模式

        装饰器顾名思义,就是在原有内容上“增添装饰品”,就像装修房子一样,先刷墙,再贴瓷砖,再安装柜子... 

        装饰器模式主要解决继承关系过于复杂的问题,通过组合来替代继承。它主要的作用是给原始类添加增强功能,这也是判断是否该用装饰器模式的一个重要的依据。除此之外,装饰器模式还有一个特点,那就是可以对原始类嵌套使用多个装饰器。为了满足这个应用场景,在设计的时候,装饰器类需要跟原始类继承相同的抽象类或者接口。装饰器类和原始类继承同样的父类,这样我们可以对原始类“嵌套”多个装饰器类。装饰器类是对功能的增强,这也是装饰器模式应用场景的一个重要特点。

        下面先看看PHP中基于接口实现一个装饰器模式的案例。

<?php

/**
 * 装饰器模式:基于接口实现
 */
interface AnyThing {
    function exe();
}

/**
 * 定义三个没有任何耦合关系的类
 */
class Moon implements AnyThing {
    private $param;

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

    public function exe() {
        echo "明月装饰了";
        $this->param->exe();
    }
}

class Dream implements AnyThing {
    private $param;

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

    public function exe() {
        echo "梦装饰了";
        $this->param->exe();
    }
}

class You implements AnyThing {
    private $param;

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

    public function exe() {
        echo "你";
    }
}


//创建对象的时候,可以通过构造函数的不同次序,使这几个类互相调用,从而呈现不同的装饰结果
$data1 = new Moon(new Dream(new You(null)));
$data1->exe(); //明月装饰了梦装饰了你
echo PHP_EOL;

$data2 = new Dream(new Moon(new You(null)));
$data2->exe(); //梦装饰了明月装饰了你
echo PHP_EOL;

代码是不是很好理解,可以按照不同的顺序去装饰,会得到不同的效果。下面再基于继承的方式实现一个装饰器模式。

假设有这么一个业务场景,作者发布一篇文章之后,可能需要 编辑人员、SEO推广人员、广告部人员分别给这篇文章增加内容,但是顺序不确定,而且增加的次数也不确定,这个时候就可以使用装饰器模式来实现。代码如下:

<?php

/**
 * 文章类
 */
class Article {
    protected $content; //文章内容
    protected $article = null; //文章对象

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

    public function decorator() {
        return $this->content;
    }

}


/**
 * 编辑人员添加摘要,继承原始的文章类
 */
class Editor extends Article {
    public function __construct(Article $article) {
        $this->article = $article;
    }

    public function decorator() {
        //调用父类的decorator方法,获取父类的content,然后再添加自己的装饰内容,下同
        $this->content = $this->article->decorator() . '【新增摘要from Editor】';
        return $this->content;
    }
}


/**
 * SEO人员添加推广信息
 */
class SEOer extends Article {
    public function __construct(Article $article) {
        $this->article = $article;
    }

    public function decorator() {
        $res = $this->content = $this->article->decorator() . '【新增推广信息from SEOer】';
        return $res;
    }
}


/**
 * 广告人员添加广告信息
 */
class ADer extends Article {
    public function __construct(Article $article) {
        $this->article = $article;
    }

    public function decorator() {
        $res = $this->content = $this->article->decorator() . '【新增广告信息from ADer】';
        return $res;
    }
}

/**
 * todo 根据需要,可以继续装饰其它内容...
 */


//客户端调用
$content = "这是一篇文章";
$article = new Article($content);
//直接发表文章,不装饰任何内容
echo $article->decorator() . PHP_EOL; //这是一篇文章

//Editor先装饰,SEOer再修饰
$client = new SEOer(new Editor($article));
echo $client->decorator() . PHP_EOL; //这是一篇文章【新增摘要from Editor】【新增推广信息from SEOer】

//SEOer先装饰,Editor再修饰,ADer最后装饰
$client = new ADer(new Editor(new SEOer($article)));
echo $client->decorator() . PHP_EOL; //这是一篇文章【新增推广信息from SEOer】【新增摘要from Editor】【新增广告信息from ADer】

//Editor修饰两遍
$client = new Editor(new Editor($article));
echo $client->decorator() . PHP_EOL; //这是一篇文章【新增摘要from Editor】【新增摘要from Editor】

其实只要理解了“装饰”的含义,就能在实际开发中联想到哪些场景可以使用装饰器模式。

源代码:https://gitee.com/rxbook/php_design_pattern/blob/master/code09_decorator1.php

https://gitee.com/rxbook/php_design_pattern/blob/master/code10_decorator2.php

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

浮尘笔记

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值