0

0

什么是装饰者模式,它与桥接模式有什么不同?

齐天大圣

齐天大圣

发布时间:2020-08-05 08:57:48

|

3316人浏览过

|

来源于php中文网

原创

拉面的故事

拉面馆里卖拉面,拉面分为小碗和大碗,小碗一份6元,大碗一份9元。另外如果加牛肉的话,则需加6元,加一个鸡蛋是1元,加大排是5元一份,加一块锅巴是1元。如果用传统的写法,设置不同价格的拉面,需要写8个类(拉面份量数*配菜数)。如果现在面馆新推一种份量——中碗,那么,就需要新增4个类。这样就会造成一个问题——类爆炸。

如果你看过我之前的文章https://www.php.cn/php-weizijiaocheng-457250.html,了解了桥接模式后,会觉得这个问题可以用桥接模式来解决。把它分为两个大类,面条和配菜。

下面我们用桥接模式来完成上述问题,代码如下:

interface INoodle
{
    function cost ();
    function desc ();
}

class BigNoodle implements INoodle
{
    private $cost = 9.0;
    private $dish = null;
    
    public function __construct(IDish $dish)
    {
        $this->dish = $dish;
    }
    
    public function cost()
    {
        return $this->cost + $this->dish->cost();
    }
    
    public function desc()
    {
        return $this->dish->desc() . '大碗拉面';
    }
}

class SmallNoodle implements INoodle
{
    private $cost = 6.0;
    private $dish = null;
    
    public function __construct(IDish $dish)
    {
        $this->dish = $dish;
    }
    
    public function cost()
    {
        return $this->cost + $this->dish->cost();
    }
    
    public function desc()
    {
        return $this->dish->desc() . '小碗拉面';
    }
}

interface IDish
{
    function cost ();
    function desc ();
}

class Beef implements IDish
{
    public function cost ()
    {
        return 6;
    }
    
    public function desc()
    {
        return '牛肉';
    }
}

class Crust implements IDish
{
    public function cost ()
    {
        return 1;
    }
    
    public function desc()
    {
        return '锅巴';
    }
}

class Egg implements IDish
{
    public function cost ()
    {
        return 1;
    }
    
    public function desc()
    {
        return '鸡蛋';
    }
}

装饰者模式

使用桥接模式确实解决了类爆炸问题,但你也知道,我们去吃面,可能有时候不要配菜,只要面,又或者我们需要多个配菜,比如,我要份大碗牛肉拉面,加3块锅巴以及2个鸡蛋。对于这种需求,使用桥接模式是完成不了的。想要解决这种问题,我们可以借助另一种结构型设计模式——装饰者模式。

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

想要理解装饰者模式,可以想象一个玩偶——套娃

202007081002215.jpg

每套一个娃,就相当于添加了一个装饰的对象。在运行时,会运行最外层的装饰对象(取外层的娃),然后一层一层的运行。现在你可能不懂什么意思,看完后面的内容然后再来会看这句话或许就会明白。

我自己画了个uml类图,有点丑,大家将就点

20200805080749.png

YXPHP6.0 豪华版
YXPHP6.0 豪华版

YXPHP6系统可以看做是一个模版平台,而且它又能独立工作. 而且YXPHP6系统也不需要数据库支持. 你可以开发自己的模板,也可以同步官方的模板后进行自己的二次开发,前提是您对YXPHP6要有一定的了解.YXPHP6不仅可以用作企业建站,甚至是blog,只要是您能想到的,YXPHP6几乎都可以胜任. 因为YXPHP6系统本身与模板之间可以说是独立运行的.也就是说,不管你做什么样的网站或者是应用,

下载

代码实现

abstract class Noodles
{
    abstract function cost ();
    abstract function desc ();
}

class BigNoodle extends Noodles
{
    private $cost = 9.0;
    
    public function cost()
    {
        return $this->cost;
    }
    
    public function desc()
    {
        return '大碗拉面';
    }
}

class SmallNoodle extends Noodles
{
    private $cost = 6.0;
    
    public function cost()
    {
        return $this->cost;
    }
    
    public function desc()
    {
        return  '小碗拉面';
    }
}

abstract class NoodlesDecorator extends Noodles
{
}

class Beef extends NoodlesDecorator
{
    private $desc = '牛肉';
    private $cost = 6.0;
    protected $noodles = null;
    
    public function __construct(Noodles $noodels)
    {
        $this->noodles = $noodels;
    }
    
    public function cost ()
    {
        return $this->cost + $this->noodles->cost();
    }
    
    public function desc ()
    {
        return $this->desc . $this->noodles->desc();
    }
}

// egg、curst类代码省略,除了属性值不一样基本和Beef一致

测试代码如下

$noodles = new BigNoodle();
$beefBigNoodles = new Beef($noodles);
$eggBeffBigNoodles = new Egg($beefBigNoodles);

echo $eggBeffBigNoodles->desc();
echo $eggBeffBigNoodles->cost() . '元';

结果输出:鸡蛋牛肉大碗拉面16元

总结

思考一个问题,为什么这里没有把拉面的份量作为装饰者对象?想想看,你会点一份既是大碗又是小碗的拉面吗?

装饰者模式特点

  • 装饰者和被装饰者对象有相同的超类型

  • 可以用一个或多个装饰者包装一个对象

  • 对象可以在任何时候被装饰,所以可以在运行时动态地、不限量地用你喜欢的装饰者来装饰对象。

相关专题

更多
菜鸟裹裹入口以及教程汇总
菜鸟裹裹入口以及教程汇总

本专题整合了菜鸟裹裹入口地址及教程分享,阅读专题下面的文章了解更多详细内容。

0

2026.01.22

Golang 性能分析与pprof调优实战
Golang 性能分析与pprof调优实战

本专题系统讲解 Golang 应用的性能分析与调优方法,重点覆盖 pprof 的使用方式,包括 CPU、内存、阻塞与 goroutine 分析,火焰图解读,常见性能瓶颈定位思路,以及在真实项目中进行针对性优化的实践技巧。通过案例讲解,帮助开发者掌握 用数据驱动的方式持续提升 Go 程序性能与稳定性。

9

2026.01.22

html编辑相关教程合集
html编辑相关教程合集

本专题整合了html编辑相关教程合集,阅读专题下面的文章了解更多详细内容。

56

2026.01.21

三角洲入口地址合集
三角洲入口地址合集

本专题整合了三角洲入口地址合集,阅读专题下面的文章了解更多详细内容。

51

2026.01.21

AO3中文版入口地址大全
AO3中文版入口地址大全

本专题整合了AO3中文版入口地址大全,阅读专题下面的的文章了解更多详细内容。

397

2026.01.21

妖精漫画入口地址合集
妖精漫画入口地址合集

本专题整合了妖精漫画入口地址合集,阅读专题下面的文章了解更多详细内容。

118

2026.01.21

java版本选择建议
java版本选择建议

本专题整合了java版本相关合集,阅读专题下面的文章了解更多详细内容。

3

2026.01.21

Java编译相关教程合集
Java编译相关教程合集

本专题整合了Java编译相关教程,阅读专题下面的文章了解更多详细内容。

16

2026.01.21

C++多线程相关合集
C++多线程相关合集

本专题整合了C++多线程相关教程,阅读专题下面的的文章了解更多详细内容。

11

2026.01.21

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
【web前端】Node.js快速入门
【web前端】Node.js快速入门

共16课时 | 2万人学习

Go语言实战之 GraphQL
Go语言实战之 GraphQL

共10课时 | 0.8万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号