🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
装饰(Decorator)模式:动态地给(具体构建的)对象增加一些职责,即在原有的基础上增加其额外的功能。 **主要优点有:** * 采用装饰模式扩展对象的功能比采用继承方式更加灵活。 * 可以设计出多个不同的具体装饰类,创造出多个不同行为的组合。 **主要缺点是:** 装饰模式增加了许多子类,如果过度使用会使程序变得很复杂。 特点:用来增强原有对象功能,依附于原有对象。 应用:用于需要对原有对象增加功能而不是完全覆盖的时候 ## 装饰模式的应用场景 其适用的应用场景,装饰模式通常在以下几种情况使用。 * 当需要给一个现有类添加附加职责,而又不能采用生成子类的方法进行扩充时。例如,该类被隐藏或者该类是终极(final)类或者采用继承方式会产生大量的子类。 * 当需要通过对现有的一组基本功能进行排列组合而产生非常多的功能时,采用继承关系很难实现,而采用装饰模式却很好实现。 * 当对象的功能要求可以动态地添加,也可以再动态地撤销时。 例:其中最常见的就是一些游戏开发商,通过去做一些装备,例如武器,衣服,鞋子,戒指等等,来吸引玩家购买,穿在身上不仅好看,还带有额外属性。 #### 1\. 模式的结构 装饰模式主要包含以下角色。 >[danger]将具体构建实例对象通过析构或者普通方法传入具体装饰类中 1. 抽象构件(Component)角色:定义一个抽象接口以规范准备接收附加责任的对象。 2. 具体构件(Concrete    Component)角色:实现(implements)抽象构件,通过装饰角色为其添加一些职责。 3. 抽象装饰(Decorator)角色:继承抽象构件,并包含具体构件的实例,可以通过其子类扩展具体构件的功能。 4. 具体装饰(ConcreteDecorator)角色:实现抽象装饰的相关方法,并给具体构件对象添加附加的责任。 ![](https://img.kancloud.cn/69/4d/694dd961ce5f4379466a88e9c118e7f4_525x540.png) ~~~ //抽象构建 interface Component { public function operation(); } //具体构建 class ConcreteComponent implements Component{ //具体组件类 public function operation() {} } //抽象装饰 abstract class Decorator implements Component{ // 装饰角色 protected $_component; public function __construct(Component $component) { $this->_component = $component; } public function operation() { $this->_component->operation(); } } //具体装饰1 class ConcreteDecoratorA extends Decorator { // 具体装饰类A public function __construct(Component $component) { parent::__construct($component); } public function operation() { parent::operation(); // 调用装饰类的操作 $this->addedOperationA(); // 执行新增加的操作方法 } //添加新的抽象方法,上面在调用 public function addedOperationA() {echo 'A加点酱油;';} } //具体装饰2 class ConcreteDecoratorB extends Decorator { // 具体装饰类B public function __construct(Component $component) { parent::__construct($component); } public function operation() { parent::operation(); $this->addedOperationB(); } public function addedOperationB() {echo "B加点辣椒;";} } // clients $component = new ConcreteComponent(); $decoratorA = new ConcreteDecoratorA($component); $decoratorB = new ConcreteDecoratorB($decoratorA); $decoratorA->operation();//输出:A加点酱油; echo '<br>--------<br>'; $decoratorB->operation();//输出:A加点酱油;B加点辣椒; ~~~ 下面这个例子是典型装饰器模式的应用,特点是在不影响其他类的情况下动态添加其它具体装备类 ``` /** 构件接口类(抽象构件类) * interface IComponent */ interface IComponent { function Display(); } /** 人物类(具体构建类) * Person */ Class Person implements IComponent { private $name; function __construct($name) { $this->name = $name; } function Display() { echo "{$this->name}当前装备:"; } } /** 装备类(抽象装饰) * Equipment */ Class Equipment implements IComponent { protected $component; function Decorator(IComponent $component) { // 动态添加 $this->component = $component; } function Display() { if(!empty($this->component)){ $this->component->Display(); } } } /** 具体装备 武器类(具体装饰) * Weapon */ Class Weapon extends Equipment { function Display(){ parent::Display(); echo "龙泉剑 "; } } /** 具体装备 戒指类(具体装饰) * Ring */ Class Ring extends Equipment { function Display(){ parent::Display(); echo "复活戒指 "; } } /** 具体装备 鞋子类(具体装饰) * Shoes */ Class Shoes extends Equipment { function Display(){ parent::Display(); echo "御风履 "; } } // 如果需要可以继续添加具体的装备 腰带 裤子 手镯 // 创建人物 $people = new Person("战士"); // 武器 $Weapon = new Weapon(); // 戒指 $Ring = new Ring(); // 鞋子 $Shoes = new Shoes(); // 动态添加函数 $Weapon->Decorator($people); $Ring->Decorator($Weapon); $Shoes->Decorator($Ring); // 显示 $Shoes->Display(); //输出结果: 战士当前装备:龙泉剑 复活戒指 御风履 ``` 游戏角色变身 ``` //抽象构件角色:莫莉卡 interface Morrigan { public function display(); } //具体构件角色:原身 class original implements Morrigan { private $img="Morrigan0.jpg"; public function __construct() { echo "《恶魔战士》中的莫莉卡·安斯兰"; } public function setImage($img) { $this->img=$img; } public function display() { $src="src/decorator/".$this->img; echo $src; } } //抽象装饰角色:变形 class Changer implements Morrigan { public $m; public function __construct(Morrigan $m) { $this->m=$m; } public function display() { $this->m->display(); } } //具体装饰角色:女妖 class Succubus extends Changer { public function __construct(Morrigan $m) { parent::__construct($m); echo "《恶魔战士》中的莫莉卡·安斯兰变身女妖"; } public function display() { $this->setChanger(); parent::display(); } //执行变身(替换形态图片) public function setChanger() { $this->m->setImage("Morrigan1.jpg"); } } //具体装饰角色:少女 class Girl extends Changer { public function __construct(Morrigan $m) { parent::__construct($m); echo "《恶魔战士》中的莫莉卡·安斯兰之变身少女"; } public function display() { $this->setChanger(); parent::display(); } //执行变身(替换形态图片) public function setChanger() { $this->m->setImage("Morrigan2.jpg"); } } class MorriganAensland { public static function main() { $m0=new original(); $m0->display(); $m1=new Succubus($m0); $m1->display(); $m2=new Girl($m0); $m2->display(); } } MorriganAensland::main(); ``` ## 装饰模式的扩展 装饰模式所包含的 4 个角色不是任何时候都要存在的,在有些应用环境下模式是可以简化的,如以下两种情况。 (1) 如果只有一个具体构件而没有抽象构件时,可以让抽象装饰继承具体构件,其结构图如图 4 所示。 ![](https://img.kancloud.cn/7d/57/7d57d24c22281e9a0b6e69284aff33e4_423x549.png) ``` //具体构件 class ConcreteComponet{ function operation(){ echo "原来的东西|"; } } //抽象装饰 class Decorator extends ConcreteComponet{ private $componet; public function __construct(ConcreteComponet $componet){ $this->componet=$componet; } public function operation(){ $this->componet->operation(); } } //具体装饰1 class ConcreteDecorator1 extends Decorator{ public function operation(){ parent::operation(); $this->addedFunction(); } public function addedFunction(){ echo "新增加的东西1|"; } } //具体装饰2 class ConcreteDecorator2 extends Decorator{ public function operation(){ parent::operation(); $this->addedFunction(); } public function addedFunction(){ echo "新增加的东西2|"; } } // clients $concreteComponet = new ConcreteComponet(); $decorator1 = new ConcreteDecorator1($concreteComponet); $decorator2 = new ConcreteDecorator2($decorator1); $decorator1->operation();//输出:原来的东西|新增加的东西1| echo '<br>--------<br>'; $decorator2->operation();//输出:原来的东西|新增加的东西1|新增加的东西2| ``` (2) 如果只有一个具体装饰时,可以将抽象装饰和具体装饰合并,其结构图如图 5 所示。 ![](https://img.kancloud.cn/33/8f/338f8348238ffc5370011f9b46791c8f_521x340.png) ``` interface Componet{ public function operation(); } //具体构件 class ConcreteComponet implements Componet{ function operation(){ echo "原来的东西|"; } } //具体装饰与抽象装饰合并 class ConcreteDecorator extends ConcreteComponet{ private $componet; public function __construct(ConcreteComponet $componet){ $this->componet=$componet; } public function operation(){ $this->componet->operation(); $this->addedFunction(); } public function addedFunction(){ echo "新增加的东西|"; } } // clients $concreteComponet = new ConcreteComponet(); $decorator = new ConcreteDecorator($concreteComponet); $decorator->operation();//输出:原来的东西|新增加的东西| ```