[TOC] #### 1. 装饰器模式 --- 装饰器模式是一种结构型设计模式,核心思想是:在不修改原有类代码的前提下,动态地给对象增加功能。 简单来说,它的核心思想是 “用组合代替继承”。当需要给一个对象添加功能时,如果直接使用继承,可能会导致子类数量呈指数级增加,而装饰器模式则像搭积木一样,可以灵活的组合各种功能。 在 PHP中实现装饰器模式,通常需要以下四种核心结构: + 组件接口:被装饰对象和装饰器必须共同实现的接口,确保它们可以互换使用 + 具体组件:实现了组件接口,是被装饰的原始对象,包含最基础的核心功能 + 抽象装饰器:同样实现了组件接口,并在内部持有一个组件对象的引用。它负责将客户端的请求委派给内部的组件对象 + 具体装饰器:继承抽象装饰器,负责在委派请求的前后,添加自己独有的额外功能 #### 2. 咖啡订单系统 --- 假设我们要开发一个咖啡订单系统,基础咖啡可以加牛奶、加糖 + 如果使用继承,我们需要创建 `MilkCoffee`、`SugarCoffee`、`MilkSugarCoffee` 等无数个子类 + 使用装饰器模式则可以优雅的解决这个问题 第一步:定义组件接口和具体组件 ```php // 1. 组件接口:定义咖啡的基本行为 interface Coffee { public function cost(): float; // 成本 public function description(): string; // 描述 } // 2. 具体组件:基础咖啡(如:意式咖啡) class SimpleCoffee implements Coffee { public function cost(): float { return 15.0; } public function description(): string { return "意式浓缩咖啡"; } } ``` 第二步:定义抽象装饰器和具体装饰器 ```php // 3. 抽象装饰器:持有 Coffee 对象的引用,并实现 Coffee 接口 abstract class CoffeeDecorator implements Coffee { protected Coffee $coffee; public function __construct(Coffee $coffee) { $this->coffee = $coffee; } } // 4. 具体装饰器:加牛奶 class MilkDecorator extends CoffeeDecorator { public function cost(): float { return $this->coffee->cost() + 5.0; // 在原有价格上增加牛奶的钱 } public function description(): string { return $this->coffee->description() . ", 加牛奶"; } } // 4. 具体装饰器:加糖 class SugarDecorator extends CoffeeDecorator { public function cost(): float { return $this->coffee->cost() + 2.0; // 在原有价格上增加糖的钱 } public function description(): string { return $this->coffee->description() . ", 加糖"; } } ``` 客户端使用(像搭积木一样组合功能) ```php // 1. 点一杯基础的意式浓缩 $myCoffee = new SimpleCoffee(); echo $myCoffee->description() . " 价格: " . $myCoffee->cost() . "元\n"; // 输出:意式浓缩咖啡 价格: 15元 // 2. 给这杯咖啡加一份牛奶 $myCoffee = new MilkDecorator($myCoffee); echo $myCoffee->description() . " 价格: " . $myCoffee->cost() . "元\n"; // 输出:意式浓缩咖啡, 加牛奶 价格: 20元 // 3. 再加一份糖(可以在之前的基础上继续包装) $myCoffee = new SugarDecorator($myCoffee); echo $myCoffee->description() . " 价格: " . $myCoffee->cost() . "元\n"; // 输出:意式浓缩咖啡, 加牛奶、加糖 价格: 22元 ``` #### 3. 装饰器模式的优缺点 --- 优点: + 符合开闭原则:可以在不修改现有代码的情况下,动态的给对象增加功能 + 灵活组合:可以通过不同的装饰器组合,创造出多种行为,避免了子类爆炸 + 单一职责:可以将复杂的功能拆分为一个个简单的装饰器类,每个类只负责一个特定功能(日志/缓存/加密) 缺点: + 代码复杂度增加:会引入许多小的装饰器类,增加了系统的复杂度 + 对象识别困难:由于装饰后的对象被层层包装,调试时追踪原始对象可能会比较麻烦