什么是装饰器模式
官方解释:装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装。
使用场景
比如一个煎饼果子,首先肯定得有一个煎饼,然后在煎饼的基础上添加葱花、香菜、脆饼、烤肠、油条等附加品。
优点
可以动态的、灵活的增删类的功能,解决继承过多的问题,符合设计原则的单一原则和开闭原则。
示意图
传统模式
装饰器模式
可以看出,传统模式用了无限继承的方式,如果附加品过多,势必会造成类的爆炸,并且如果要修改中间的附加品,也需要修改继承这个附加品的类,比如顾客想要去掉香菜,那么脆饼、油条、香肠这三个类都会收到影响,很不灵活,厨师也会很烦。
装饰器模式就是用来解决这些问题的,可以看到所有的附加品只继承一个共有的抽象类,煎饼类被单独封装了出来,此时除了附加品抽象类的修改之外,其他每个类都有自己的职责且互不影响,可以给煎饼灵活的新增附加品。
当然文字解释只是为了让人加深印象,具体想弄明白,还得看代码,并且在项目中多用多练
代码实例
目录结构
Jianbing.php 煎饼类
<?php
/**
* 煎饼类
* Class Jianbing
*/
class Jianbing{
public $name;
public $fujiapin=[];
//初始化煎饼名称
public function __construct($name)
{
$this->name = $name;
}
//添加附加品
public function addFujiapin(Fujiapin $fujiapin){
$this->fujiapin[] = $fujiapin;
}
//得到最终的煎饼
public function get(){
echo $this->name;
foreach ($this->fujiapin as $fujiapin){
echo "<br>";
$fujiapin->get();
}
}
}
Fujiapin.php 附加品抽象类
/**
* 附加品抽象类
* Class Fujiapin
*/
abstract class Fujiapin{
//获取附加品
abstract function get();
}
Conghua.php 葱花类
class Conghua extends Fujiapin{
public function get()
{
// TODO: Implement get() method.
echo "加葱花";
}
}
Xiangcai.php 香菜类
class Xiangcai extends Fujiapin{
public function get()
{
// TODO: Implement get() method.
echo "加香菜";
}
}
Youtiao.php 油条类
class Youtiao extends Fujiapin{
public function get()
{
// TODO: Implement get() method.
echo "加油条";
}
}
kaochang.php 烤肠类
<?php
class Kaochang extends Fujiapin{
public function get()
{
// TODO: Implement get() method.
echo "加烤肠";
}
}
Cuibing.php 脆饼类
class Cuibing extends Fujiapin{
public function get()
{
// TODO: Implement get() method.
echo "加脆饼";
}
}
Client.php 调用
<?php
require_once 'Fujiapin.php';
require_once 'Conghua.php';
require_once 'Kaochang.php';
require_once 'Jianbing.php';
require_once 'Youtiao.php';
require_once 'Cuibing.php';
require_once 'Xiangcai.php';
$jianbing = new Jianbing('煎饼');
$conghua = new Conghua();
$xiangcai = new Xiangcai();
$youtiao = new Youtiao();
$jianbing->addFujiapin($conghua);//添加葱花
$jianbing->addFujiapin($xiangcai);//添加香菜
$jianbing->addFujiapin($youtiao);//添加油条
$jianbing->get();
运行结果