PHP设计模式装饰器与代理实践
2026/6/2 6:02:32 网站建设 项目流程

PHP设计模式装饰器与代理实践

装饰器模式和代理模式在结构上有些相似,但目的完全不同。装饰器动态添加功能,代理控制访问。今天用实际代码说明两者的区别。

装饰器模式的核心是层层包装,每个装饰器添加一点功能。

```php
interface NotificationInterface
{
public function send(string $message): void;
}

class BasicNotification implements NotificationInterface
{
public function send(string $message): void
{
echo "发送消息: $message\n";
}
}

abstract class NotificationDecorator implements NotificationInterface
{
protected NotificationInterface $notification;

public function __construct(NotificationInterface $notification)
{
$this->notification = $notification;
}
}

class EmailDecorator extends NotificationDecorator
{
private string $email;

public function __construct(NotificationInterface $notification, string $email)
{
parent::__construct($notification);
$this->email = $email;
}

public function send(string $message): void
{
$this->notification->send($message);
echo "发送邮件至 {$this->email}: $message\n";
}
}

class SmsDecorator extends NotificationDecorator
{
private string $phone;

public function __construct(NotificationInterface $notification, string $phone)
{
parent::__construct($notification);
$this->phone = $phone;
}

public function send(string $message): void
{
$this->notification->send($message);
echo "发送短信至 {$this->phone}: $message\n";
}
}

class SlackDecorator extends NotificationDecorator
{
private string $channel;

public function __construct(NotificationInterface $notification, string $channel)
{
parent::__construct($notification);
$this->channel = $channel;
}

public function send(string $message): void
{
$this->notification->send($message);
echo "发送Slack消息到 {$this->channel}: $message\n";
}
}

class LogDecorator extends NotificationDecorator
{
public function send(string $message): void
{
echo "[日志] 开始发送通知\n";
$this->notification->send($message);
echo "[日志] 通知发送完成\n";
}
}

$notification = new BasicNotification();
$notification = new EmailDecorator($notification, 'user@example.com');
$notification = new SmsDecorator($notification, '13800138000');
$notification = new SlackDecorator($notification, '#general');
$notification = new LogDecorator($notification);

$notification->send('系统更新通知');
?>
```

代理模式在需要控制对对象的访问时使用。常见的代理类型有虚拟代理、保护代理、远程代理等。

```php
interface ImageInterface
{
public function display(): void;
public function getSize(): array;
}

class RealImage implements ImageInterface
{
private string $filename;
private int $width;
private int $height;

public function __construct(string $filename)
{
$this->filename = $filename;
$this->loadFromDisk();
}

private function loadFromDisk(): void
{
echo "从磁盘加载图片: {$this->filename}\n";
$this->width = 1920;
$this->height = 1080;
}

public function display(): void
{
echo "显示图片: {$this->filename} ({$this->width}x{$this->height})\n";
}

public function getSize(): array
{
return ['width' => $this->width, 'height' => $this->height];
}
}

class ImageProxy implements ImageInterface
{
private ?RealImage $realImage = null;
private int $accessCount = 0;

public function __construct(
private string $filename
) {}

public function display(): void
{
$this->accessCount++;
echo "代理记录: 第{$this->accessCount}次访问\n";

if ($this->realImage === null) {
$this->realImage = new RealImage($this->filename);
}

$this->realImage->display();
}

public function getSize(): array
{
if ($this->realImage === null) {
return ['width' => 0, 'height' => 0, 'note' => '图片尚未加载'];
}
return $this->realImage->getSize();
}

public function getAccessCount(): int
{
return $this->accessCount;
}
}

$image = new ImageProxy('photo.jpg');
echo "图片信息: " . json_encode($image->getSize()) . "\n";
$image->display();
$image->display();
echo "访问次数: {$image->getAccessCount()}\n";
?>
```

保护代理控制访问权限:

```php
interface DocumentInterface
{
public function getContent(): string;
public function getMetadata(): array;
}

class Document implements DocumentInterface
{
public function __construct(
private int $id,
private string $content,
private array $metadata = []
) {}

public function getContent(): string
{
return $this->content;
}

public function getMetadata(): array
{
return $this->metadata;
}
}

class DocumentProxy implements DocumentInterface
{
private ?Document $document = null;
private array $permissions;

public function __construct(
int $id,
string $content,
private string $owner,
array $permissions = []
) {
$this->permissions = $permissions;
$this->document = new Document($id, $content, ['owner' => $owner]);
}

public function getContent(): string
{
if (!$this->hasPermission('read')) {
throw new RuntimeException('没有读取权限');
}
return $this->document->getContent();
}

public function getMetadata(): array
{
return $this->document->getMetadata();
}

public function setPermission(string $user, string $perm): void
{
if ($user === $this->owner) {
$this->permissions[$user][] = $perm;
}
}

private function hasPermission(string $perm): bool
{
$userPerms = $this->permissions[$this->owner] ?? [];
return in_array($perm, $userPerms);
}
}

$doc = new DocumentProxy(1, '机密内容', '张三', ['张三' => ['read']]);
echo $doc->getMetadata()['owner'] . "的文档\n";
echo $doc->getContent() . "\n";
?>
```

装饰器和代理的主要区别是用途不同。装饰器用于增强功能,代理用于控制访问。在实现上,装饰器通常接收被装饰对象作为构造参数,代理则自己创建或引用目标对象。理解了这两种模式的区别,在实际项目中就能根据需求选择合适的方案。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询