本文目录导读:

我来详细解释如何使用状态模式重构复杂条件逻辑,并提供实际示例。
什么是状态模式
状态模式允许对象在内部状态改变时改变其行为,看起来就像修改了对象的类一样,主要解决复杂条件判断(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. 如果状态不多且简单,直接使用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();
}
}
状态模式最适合:
- 操作包含庞大的多分支条件语句
- 对象的行为依赖于它的状态,并随着状态改变而改变
- 状态转换规则复杂且需要统一管理
通过这个重构示例,可以看到状态模式如何显著提升代码的可维护性和可扩展性,关键在于将状态和对应行为封装为独立对象,使状态转换变得显式且安全。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播