设计模式是软件开发中经过验证的解决方案模板,它们帮助我们以更优雅、可维护的方式组织代码。在 PHP 开发中,策略模式、观察者模式和装饰器模式是三种最常用且实用的设计模式。本文将通过实际场景和代码示例,深入探讨这三种模式的应用。
一、策略模式(Strategy Pattern)
1.1 什么是策略模式
策略模式定义了一系列算法,将每个算法封装起来,并使它们可以相互替换。策略模式让算法的变化独立于使用算法的客户端。
1.2 实际应用场景
假设我们正在开发一个电商系统,需要根据不同的用户类型计算商品折扣价格。普通用户享受 95 折,VIP 用户享受 8 折,超级 VIP 享受 7 折。
1.3 代码实现
首先定义策略接口:
<?php
interface DiscountStrategy
{
public function calculate(float $price): float;
}
然后实现具体的折扣策略:
class NormalUserDiscount implements DiscountStrategy
{
public function calculate(float $price): float
{
return $price * 0.95;
}
}
class VipUserDiscount implements DiscountStrategy
{
public function calculate(float $price): float
{
return $price * 0.80;
}
}
class SuperVipDiscount implements DiscountStrategy
{
public function calculate(float $price): float
{
return $price * 0.70;
}
}
创建上下文类来使用策略:
class PriceCalculator
{
private DiscountStrategy $strategy;
public function setStrategy(DiscountStrategy $strategy): void
{
$this->strategy = $strategy;
}
public function getFinalPrice(float $price): float
{
return $this->strategy->calculate($price);
}
}
使用示例:
$calculator = new PriceCalculator();
$calculator->setStrategy(new VipUserDiscount());
echo $calculator->getFinalPrice(1000); // 输出 800
$calculator->setStrategy(new SuperVipDiscount());
echo $calculator->getFinalPrice(1000); // 输出 700
1.4 优势总结
- 开闭原则:新增折扣类型无需修改现有代码
- 消除条件语句:避免大量的 if-else 或 switch-case
- 算法独立:每个策略类职责单一,便于测试
二、观察者模式(Observer Pattern)
2.1 什么是观察者模式
观察者模式定义了一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖它的对象都会收到通知并自动更新。
2.2 实际应用场景
在用户注册系统中,注册成功后需要执行多个操作:发送欢迎邮件、记录日志、发放新人优惠券。使用观察者模式可以将这些操作解耦。
2.3 代码实现
首先定义观察者接口和主题接口:
interface Observer
{
public function update(string $event, array $data): void;
}
interface Subject
{
public function attach(Observer $observer): void;
public function detach(Observer $observer): void;
public function notify(string $event, array $data): void;
}
实现具体的主题类:
class UserRegistration implements Subject
{
private array $observers = [];
public function attach(Observer $observer): void
{
$this->observers[] = $observer;
}
public function detach(Observer $observer): void
{
$index = array_search($observer, $this->observers, true);
if ($index !== false) {
unset($this->observers[$index]);
$this->observers = array_values($this->observers);
}
}
public function notify(string $event, array $data): void
{
foreach ($this->observers as $observer) {
$observer->update($event, $data);
}
}
public function register(string $username, string $email): void
{
// 执行注册逻辑
echo "用户 {$username} 注册成功\n";
// 通知所有观察者
$this->notify('user.registered', [
'username' => $username,
'email' => $email,
]);
}
}
实现具体的观察者:
class WelcomeEmailObserver implements Observer
{
public function update(string $event, array $data): void
{
if ($event === 'user.registered') {
echo "发送欢迎邮件到 {$data['email']}\n";
}
}
}
class LogObserver implements Observer
{
public function update(string $event, array $data): void
{
echo "记录日志:事件 {$event},用户 {$data['username']}\n";
}
}
class CouponObserver implements Observer
{
public function update(string $event, array $data): void
{
if ($event === 'user.registered') {
echo "为用户 {$data['username']} 发放新人优惠券\n";
}
}
}
使用示例:
$registration = new UserRegistration();
$registration->attach(new WelcomeEmailObserver());
$registration->attach(new LogObserver());
$registration->attach(new CouponObserver());
$registration->register('张三', 'zhangsan@example.com');
2.4 优势总结
- 松耦合:主题与观察者之间互不依赖具体实现
- 可扩展性:新增观察者无需修改主题代码
- 符合开闭原则:对扩展开放,对修改关闭
三、装饰器模式(Decorator Pattern)
3.1 什么是装饰器模式
装饰器模式允许向一个现有的对象添加新的功能,同时不改变其结构。这种模式创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供额外的功能。
3.2 实际应用场景
在日志系统中,我们可能需要将日志输出到不同地方(文件、数据库、控制台),并且可能需要添加时间戳、格式化等额外处理。
3.3 代码实现
定义日志接口:
interface Logger
{
public function log(string $message): string;
}
基础实现:
class FileLogger implements Logger
{
public function log(string $message): string
{
return "[文件日志] {$message}";
}
}
class DatabaseLogger implements Logger
{
public function log(string $message): string
{
return "[数据库日志] {$message}";
}
}
创建装饰器基类:
abstract class LoggerDecorator implements Logger
{
protected Logger $logger;
public function __construct(Logger $logger)
{
$this->logger = $logger;
}
public function log(string $message): string
{
return $this->logger->log($message);
}
}
实现具体装饰器:
class TimestampDecorator extends LoggerDecorator
{
public function log(string $message): string
{
$timestamp = date('Y-m-d H:i:s');
return $this->logger->log("[{$timestamp}] {$message}");
}
}
class JsonFormatDecorator extends LoggerDecorator
{
public function log(string $message): string
{
$formatted = json_encode(['message' => $message, 'level' => 'info']);
return $this->logger->log($formatted);
}
}
class UppercaseDecorator extends LoggerDecorator
{
public function log(string $message): string
{
return $this->logger->log(strtoupper($message));
}
}
使用示例:
// 基础日志
$logger = new FileLogger();
echo $logger->log("系统启动") . "\n";
// 添加时间戳装饰
$logger = new TimestampDecorator(new FileLogger());
echo $logger->log("系统启动") . "\n";
// 叠加多个装饰器
$logger = new UppercaseDecorator(
new TimestampDecorator(
new JsonFormatDecorator(
new DatabaseLogger()
)
)
);
echo $logger->log("用户登录") . "\n";
3.4 优势总结
- 灵活性:可以动态地添加或删除功能
- 组合优于继承:避免类爆炸问题
- 单一职责:每个装饰器只关注一个功能
四、三种模式的对比与选择
| 模式 | 核心思想 | 适用场景 |
|---|---|---|
| 策略模式 | 封装可互换的算法 | 多种业务规则切换、支付方式选择 |
| 观察者模式 | 一对多依赖通知 | 事件系统、消息推送、钩子机制 |
| 装饰器模式 | 动态添加功能 | 日志处理、中间件、数据流处理 |
五、总结
设计模式不是银弹,而是帮助我们更好地组织代码的工具。在实际开发中:
- 策略模式适合处理同一问题的不同算法实现,避免冗长的条件判断
- 观察者模式适合构建事件驱动架构,实现模块间的松耦合
- 装饰器模式适合在不修改原有类的前提下,灵活地扩展功能
掌握这三种模式,能够显著提升 PHP 代码的可维护性和可扩展性。建议在实际项目中多加练习,根据具体场景灵活运用,而非为了使用模式而使用模式。
未经允许不得转载:任鹏个人博客 » PHP 中的设计模式实战:策略模式、观察者模式与装饰器模式


朋友圈点赞图在线生成源码