PHP状态模式重构条件

wen PHP项目 6

本文目录导读:

PHP状态模式重构条件

  1. 什么是状态模式
  2. 问题场景示例
  3. 状态模式重构
  4. 状态模式的核心优点
  5. 状态模式的缺点和注意事项
  6. 进阶:结合工厂模式

我来详细解释如何使用状态模式重构复杂条件逻辑,并提供实际示例。

什么是状态模式

状态模式允许对象在内部状态改变时改变其行为,看起来就像修改了对象的类一样,主要解决复杂条件判断(if-else / switch)导致的代码臃肿问题。

问题场景示例

原始代码(使用大量条件判断)

<?php
class Order
{
    const STATUS_NEW = 'new';
    const STATUS_PAID = 'paid';
    const STATUS_SHIPPED = 'shipped';
    const STATUS_COMPLETED = 'completed';
    const STATUS_CANCELLED = 'cancelled';
    private string $status;
    public function __construct()
    {
        $this->status = self::STATUS_NEW;
    }
    // 支付操作
    public function pay(): void
    {
        if ($this->status === self::STATUS_NEW) {
            echo "订单支付成功\n";
            $this->status = self::STATUS_PAID;
        } elseif ($this->status === self::STATUS_PAID) {
            echo "订单已支付,不能重复支付\n";
        } elseif ($this->status === self::STATUS_SHIPPED) {
            echo "订单已发货,不能支付\n";
        } elseif ($this->status === self::STATUS_COMPLETED) {
            echo "订单已完成,不能支付\n";
        } elseif ($this->status === self::STATUS_CANCELLED) {
            echo "订单已取消,不能支付\n";
        } else {
            throw new \Exception("未知状态");
        }
    }
    // 发货操作(继续膨胀...)
    public function ship(): void
    {
        if ($this->status === self::STATUS_PAID) {
            echo "订单发货成功\n";
            $this->status = self::STATUS_SHIPPED;
        } elseif ($this->status === self::STATUS_NEW) {
            echo "订单未支付,不能发货\n";
        } elseif ($this->status === self::STATUS_SHIPPED) {
            echo "订单已发货,不能重复发货\n";
        } elseif ($this->status === self::STATUS_COMPLETED) {
            echo "订单已完成,不能发货\n";
        } elseif ($this->status === self::STATUS_CANCELLED) {
            echo "订单已取消,不能发货\n";
        } else {
            throw new \Exception("未知状态");
        }
    }
    // 完成操作(继续膨胀...)
    public function complete(): void
    {
        if ($this->status === self::STATUS_SHIPPED) {
            echo "订单完成\n";
            $this->status = self::STATUS_COMPLETED;
        } elseif ($this->status === self::STATUS_NEW) {
            echo "订单未发货,不能完成\n";
        } elseif ($this->status === self::STATUS_PAID) {
            echo "订单未发货,不能完成\n";
        } elseif ($this->status === self::STATUS_COMPLETED) {
            echo "订单已完成,不能重复完成\n";
        } elseif ($this->status === self::STATUS_CANCELLED) {
            echo "订单已取消,不能完成\n";
        } else {
            throw new \Exception("未知状态");
        }
    }
}

问题

  • 每个方法都有大量if-else嵌套
  • 添加新状态需要修改所有方法
  • 代码可读性差,维护困难

状态模式重构

定义状态接口

<?php
// 订单状态接口
interface OrderStateInterface
{
    // 执行支付操作
    public function pay(OrderContext $order): void;
    // 执行发货操作
    public function ship(OrderContext $order): void;
    // 执行完成操作
    public function complete(OrderContext $order): void;
    // 执行取消操作
    public function cancel(OrderContext $order): void;
    // 获取当前状态名
    public function getStatusName(): string;
}

实现具体状态类

<?php
// 新订单状态
class NewOrderState implements OrderStateInterface
{
    public function pay(OrderContext $order): void
    {
        echo "订单支付成功\n";
        $order->setState(new PaidOrderState());
    }
    public function ship(OrderContext $order): void
    {
        echo "订单未支付,不能发货\n";
    }
    public function complete(OrderContext $order): void
    {
        echo "订单未发货,不能完成\n";
    }
    public function cancel(OrderContext $order): void
    {
        echo "订单取消成功\n";
        $order->setState(new CancelledOrderState());
    }
    public function getStatusName(): string
    {
        return "新订单";
    }
}
// 已支付状态
class PaidOrderState implements OrderStateInterface
{
    public function pay(OrderContext $order): void
    {
        echo "订单已支付,不能重复支付\n";
    }
    public function ship(OrderContext $order): void
    {
        echo "订单发货成功\n";
        $order->setState(new ShippedOrderState());
    }
    public function complete(OrderContext $order): void
    {
        echo "订单未发货,不能完成\n";
    }
    public function cancel(OrderContext $order): void
    {
        echo "订单已支付,不能取消\n";
    }
    public function getStatusName(): string
    {
        return "已支付";
    }
}
// 已发货状态
class ShippedOrderState implements OrderStateInterface
{
    public function pay(OrderContext $order): void
    {
        echo "订单已发货,不能支付\n";
    }
    public function ship(OrderContext $order): void
    {
        echo "订单已发货,不能重复发货\n";
    }
    public function complete(OrderContext $order): void
    {
        echo "订单完成成功\n";
        $order->setState(new CompletedOrderState());
    }
    public function cancel(OrderContext $order): void
    {
        echo "订单已发货,不能取消\n";
    }
    public function getStatusName(): string
    {
        return "已发货";
    }
}
// 已完成状态
class CompletedOrderState implements OrderStateInterface
{
    public function pay(OrderContext $order): void
    {
        echo "订单已完成,不能支付\n";
    }
    public function ship(OrderContext $order): void
    {
        echo "订单已完成,不能发货\n";
    }
    public function complete(OrderContext $order): void
    {
        echo "订单已完成,不能重复完成\n";
    }
    public function cancel(OrderContext $order): void
    {
        echo "订单已完成,不能取消\n";
    }
    public function getStatusName(): string
    {
        return "已完成";
    }
}
// 已取消状态
class CancelledOrderState implements OrderStateInterface
{
    public function pay(OrderContext $order): void
    {
        echo "订单已取消,不能支付\n";
    }
    public function ship(OrderContext $order): void
    {
        echo "订单已取消,不能发货\n";
    }
    public function complete(OrderContext $order): void
    {
        echo "订单已取消,不能完成\n";
    }
    public function cancel(OrderContext $order): void
    {
        echo "订单已取消,不能重复取消\n";
    }
    public function getStatusName(): string
    {
        return "已取消";
    }
}

创建上下文类

<?php
class OrderContext
{
    private OrderStateInterface $state;
    // 订单数据
    private array $orderData = [];
    public function __construct()
    {
        $this->state = new NewOrderState();
    }
    public function setState(OrderStateInterface $state): void
    {
        $this->state = $state;
    }
    // 委托操作给当前状态
    public function pay(): void
    {
        $this->state->pay($this);
    }
    public function ship(): void
    {
        $this->state->ship($this);
    }
    public function complete(): void
    {
        $this->state->complete($this);
    }
    public function cancel(): void
    {
        $this->state->cancel($this);
    }
    // 获取当前状态
    public function getStatusName(): string
    {
        return $this->state->getStatusName();
    }
    // 设置订单数据
    public function setData(string $key, $value): void
    {
        $this->orderData[$key] = $value;
    }
    public function getData(string $key)
    {
        return $this->orderData[$key] ?? null;
    }
}

使用示例

<?php
// 使用重构后的代码
$order = new OrderContext();
$order->setData('order_no', '2024001');
echo "初始状态:" . $order->getStatusName() . "\n";
// 模拟订单流程
$order->pay();      // 输出:订单支付成功
echo "当前状态:" . $order->getStatusName() . "\n";
$order->pay();      // 输出:订单已支付,不能重复支付
$order->ship();     // 输出:订单发货成功
echo "当前状态:" . $order->getStatusName() . "\n";
$order->complete(); // 输出:订单完成成功
echo "当前状态:" . $order->getStatusName() . "\n";
// 测试取消场景
$order2 = new OrderContext();
$order2->pay();
echo "当前状态:" . $order2->getStatusName() . "\n";
$order2->cancel();  // 输出:订单已支付,不能取消
$order2->ship();
echo "当前状态:" . $order2->getStatusName() . "\n";
$order2->cancel();  // 输出:订单已发货,不能取消

状态模式的核心优点

开闭原则

  • 新增状态时只需添加新状态类,无需修改现有代码
  • 完全符合"对扩展开放,对修改关闭"

消除条件判断

  • 移除大量的if-else/switch语句
  • 状态行为被分散到各自的状态类中

代码组织清晰

  • 每个状态的行为集中在一个类中
  • 状态转换逻辑单一明确

状态一致性

  • 状态转换被封装在状态类中
  • 避免了非法状态转换

状态模式的缺点和注意事项

缺点

  1. 类数量增多:每个状态都需要一个类
  2. 状态转换分散:转换逻辑分布在各个状态类中

使用建议

// 1. 如果状态不多且简单,直接使用enum + switch即可
enum OrderStatus {
    case NEW;
    case PAID;
    case SHIPPED;
}
// 简单场景不需要状态模式
function checkOrderStatus(OrderStatus $status) {
    switch ($status) {
        case OrderStatus::NEW:
            // do something
            break;
        case OrderStatus::PAID:
            // do something
            break;
    }
}
// 2. 当状态转换逻辑复杂、每个状态有大量行为时,使用状态模式
// 3. 状态数量较多且经常变化时,考虑状态模式

进阶:结合工厂模式

<?php
// 状态工厂(可选,用于从数据库恢复状态)
class OrderStateFactory
{
    public static function createState(string $status): OrderStateInterface
    {
        return match ($status) {
            'new' => new NewOrderState(),
            'paid' => new PaidOrderState(),
            'shipped' => new ShippedOrderState(),
            'completed' => new CompletedOrderState(),
            'cancelled' => new CancelledOrderState(),
            default => throw new \InvalidArgumentException("未知状态: {$status}"),
        };
    }
}
// 增强的OrderContext
class AdvancedOrderContext
{
    private OrderStateInterface $state;
    public function restoreState(string $status): void
    {
        $this->state = OrderStateFactory::createState($status);
    }
    // 保存状态(用于持久化)
    public function getCurrentState(): string
    {
        return $this->state->getStatusName();
    }
}

状态模式最适合:

  • 操作包含庞大的多分支条件语句
  • 对象的行为依赖于它的状态,并随着状态改变而改变
  • 状态转换规则复杂且需要统一管理

通过这个重构示例,可以看到状态模式如何显著提升代码的可维护性和可扩展性,关键在于将状态和对应行为封装为独立对象,使状态转换变得显式且安全。

抱歉,评论功能暂时关闭!