拉面的故事

拉面馆里卖拉面,拉面分为小碗和大碗,小碗一份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

代码实现

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元

总结

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

装饰者模式特点

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

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

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

更多相关文章

  1. php设计模式:桥接模式学习心得(附案例代码)
  2. 什么是适配器模式,它有哪些应用场景
  3. PHP设计模式之简单工厂模式
  4. php设计模式之组合模式——处理树形结构数据
  5. 使用注册树及工厂模式来替代使用单例模式实践(附案例)
  6. 一文读懂php设计模式之代理模式
  7. 一文读懂php设计模式之责任链模式
  8. 一文读懂php设计模式之模板方法模式
  9. php的设计模式是什么意思

随机推荐

  1. [置顶] Python-uiautomator使用说
  2. 从json获取最大插槽并应用于控制器
  3. 路飞学城Python-Day9(practise)
  4. Python学习笔记(十四)
  5. 彷徨中的成长-记一个文科生的IT成长过程
  6. Python note1(语言语义)
  7. 使用python实现菱形的两种方法
  8. javascript类定义与对象的性能
  9. Win7 64为Sublime Text3 配置python3的开
  10. 一个在线音乐软件的故事(三、音乐从哪里来