本文目录导读:

我来详细介绍PHP装饰器模式的实现和用法。
装饰器模式概念
装饰器模式允许在不修改现有类的情况下,动态地给对象添加新的功能,它通过包装现有对象来扩展功能。
基础实现
基础组件接口和实现
<?php
// 饮料接口
interface Beverage {
public function getDescription(): string;
public function getCost(): float;
}
// 具体组件:咖啡
class Coffee implements Beverage {
protected $description = '普通咖啡';
protected $cost = 10.0;
public function getDescription(): string {
return $this->description;
}
public function getCost(): float {
return $this->cost;
}
}
// 具体组件:茶
class Tea implements Beverage {
protected $description = '原味茶';
protected $cost = 8.0;
public function getDescription(): string {
return $this->description;
}
public function getCost(): float {
return $this->cost;
}
}
装饰器基类
<?php
// 抽象装饰器
abstract class BeverageDecorator implements Beverage {
protected $beverage;
public function __construct(Beverage $beverage) {
$this->beverage = $beverage;
}
}
具体装饰器
<?php
// 加牛奶装饰器
class MilkDecorator extends BeverageDecorator {
public function getDescription(): string {
return $this->beverage->getDescription() . ' + 牛奶';
}
public function getCost(): float {
return $this->beverage->getCost() + 3.0;
}
}
// 加糖装饰器
class SugarDecorator extends BeverageDecorator {
public function getDescription(): string {
return $this->beverage->getDescription() . ' + 糖';
}
public function getCost(): float {
return $this->beverage->getCost() + 1.5;
}
}
// 加奶油装饰器
class WhipDecorator extends BeverageDecorator {
public function getDescription(): string {
return $this->beverage->getDescription() . ' + 奶油';
}
public function getCost(): float {
return $this->beverage->getCost() + 4.0;
}
}
// 加珍珠装饰器
class BubbleDecorator extends BeverageDecorator {
public function getDescription(): string {
return $this->beverage->getDescription() . ' + 珍珠';
}
public function getCost(): float {
return $this->beverage->getCost() + 2.5;
}
}
使用示例
基础使用
<?php // 创建一个基础咖啡 $coffee = new Coffee(); echo $coffee->getDescription() . ":¥" . $coffee->getCost() . "\n"; // 输出:普通咖啡:¥10 // 给咖啡加牛奶 $coffeeWithMilk = new MilkDecorator($coffee); echo $coffeeWithMilk->getDescription() . ":¥" . $coffeeWithMilk->getCost() . "\n"; // 输出:普通咖啡 + 牛奶:¥13 // 继续加糖 $coffeeWithMilkAndSugar = new SugarDecorator($coffeeWithMilk); echo $coffeeWithMilkAndSugar->getDescription() . ":¥" . $coffeeWithMilkAndSugar->getCost() . "\n"; // 输出:普通咖啡 + 牛奶 + 糖:¥14.5
链式使用
<?php
// 使用链式调用创建复杂组合
$bubbleTea = new BubbleDecorator(
new SugarDecorator(
new MilkDecorator(
new Tea()
)
)
);
echo $bubbleTea->getDescription() . ":¥" . $bubbleTea->getCost() . "\n";
// 输出:原味茶 + 牛奶 + 糖 + 珍珠:¥15
更实用的示例:权限系统
<?php
// 权限组件接口
interface Permission {
public function check(string $action): bool;
public function getPermissions(): array;
}
// 基础权限
class BasePermission implements Permission {
protected array $permissions = ['view'];
public function check(string $action): bool {
return in_array($action, $this->permissions);
}
public function getPermissions(): array {
return $this->permissions;
}
}
// 权限装饰器基类
abstract class PermissionDecorator implements Permission {
protected Permission $permission;
public function __construct(Permission $permission) {
$this->permission = $permission;
}
public function check(string $action): bool {
return $this->permission->check($action);
}
public function getPermissions(): array {
return $this->permission->getPermissions();
}
}
// 添加编辑权限
class EditPermissionDecorator extends PermissionDecorator {
public function check(string $action): bool {
if ($action === 'edit') {
return true;
}
return parent::check($action);
}
public function getPermissions(): array {
$permissions = parent::getPermissions();
$permissions[] = 'edit';
return array_unique($permissions);
}
}
// 添加删除权限
class DeletePermissionDecorator extends PermissionDecorator {
public function check(string $action): bool {
if ($action === 'delete') {
return true;
}
return parent::check($action);
}
public function getPermissions(): array {
$permissions = parent::getPermissions();
$permissions[] = 'delete';
return array_unique($permissions);
}
}
// 添加管理权限
class AdminPermissionDecorator extends PermissionDecorator {
public function check(string $action): bool {
// 管理员拥有所有权限
return true;
}
public function getPermissions(): array {
return ['view', 'edit', 'delete', 'manage', 'settings'];
}
}
// 使用示例
$userPermission = new BasePermission();
$editorPermission = new EditPermissionDecorator($userPermission);
$adminPermission = new AdminPermissionDecorator($userPermission);
echo $userPermission->check('edit') ? '可以编辑' : '不能编辑'; // 不能编辑
echo $editorPermission->check('edit') ? '可以编辑' : '不能编辑'; // 可以编辑
echo $adminPermission->check('delete') ? '可以删除' : '不能删除'; // 可以删除
高级特性:动态添加方法
<?php
// 使用魔术方法实现动态扩展
class DynamicDecorator {
protected $wrapped;
protected $extras = [];
public function __construct($wrapped) {
$this->wrapped = $wrapped;
}
public function addExtra(string $name, callable $callable) {
$this->extras[$name] = $callable;
return $this;
}
public function __call($method, $arguments) {
// 先尝试调用包装对象的方法
if (method_exists($this->wrapped, $method)) {
return $this->wrapped->$method(...$arguments);
}
// 检查是否有扩展方法
if (isset($this->extras[$method])) {
return call_user_func_array($this->extras[$method], $arguments);
}
throw new BadMethodCallException("方法 $method 不存在");
}
public function __get($name) {
if (property_exists($this->wrapped, $name)) {
return $this->wrapped->$name;
}
return null;
}
public function __set($name, $value) {
$this->wrapped->$name = $value;
}
}
// 使用示例
class Order {
public $total = 100;
public function getTotal() {
return $this->total;
}
}
$order = new Order();
$orderDecorator = (new DynamicDecorator($order))
->addExtra('withDiscount', function($percent) {
return $this->getTotal() * (1 - $percent/100);
})
->addExtra('withTax', function() {
return $this->getTotal() * 1.1;
});
echo $orderDecorator->getTotal(); // 调用原始方法
echo $orderDecorator->withDiscount(20); // 调用扩展方法
优缺点
优点
- 动态添加功能,灵活性高
- 遵循开闭原则,无需修改现有代码
- 可以组合多个装饰器,实现丰富功能
- 避免创建过多子类
缺点
- 会产生大量小类
- 增加系统复杂度
- 调试困难(多层嵌套)
- 性能有一定影响
实际应用场景
<?php
// 缓存装饰器示例
interface CacheInterface {
public function get(string $key);
public function set(string $key, $value, int $ttl = 3600);
}
class RedisCache implements CacheInterface {
public function get(string $key) {
// Redis 获取逻辑
return "data from redis";
}
public function set(string $key, $value, int $ttl = 3600) {
// Redis 设置逻辑
return true;
}
}
// 日志装饰器
class LoggingCacheDecorator implements CacheInterface {
protected $cache;
protected $logFile;
public function __construct(CacheInterface $cache, string $logFile) {
$this->cache = $cache;
$this->logFile = $logFile;
}
public function get(string $key) {
$start = microtime(true);
$result = $this->cache->get($key);
$this->log("GET $key", microtime(true) - $start);
return $result;
}
public function set(string $key, $value, int $ttl = 3600) {
$result = $this->cache->set($key, $value, $ttl);
$this->log("SET $key");
return $result;
}
protected function log(string $message, float $time = 0) {
$log = sprintf("[%s] %s (%.4fs)\n", date('Y-m-d H:i:s'), $message, $time);
file_put_contents($this->logFile, $log, FILE_APPEND);
}
}
// 压缩装饰器
class CompressCacheDecorator implements CacheInterface {
protected $cache;
public function __construct(CacheInterface $cache) {
$this->cache = $cache;
}
public function get(string $key) {
$data = $this->cache->get($key);
return $data ? gzuncompress($data) : null;
}
public function set(string $key, $value, int $ttl = 3600) {
$compressed = gzcompress($value);
return $this->cache->set($key, $compressed, $ttl);
}
}
// 使用
$cache = new RedisCache();
$cache = new LoggingCacheDecorator($cache, '/tmp/cache.log');
$cache = new CompressCacheDecorator($cache);
// $cache 同时具有日志和压缩功能
装饰器模式是PHP中非常实用的设计模式,特别适合需要动态添加功能的场景,如权限管理、缓存增强、日志记录等。