State 状态模式可以基于一个对象的同种事务而封装出不同的行为

它提供一种简洁的方式使得对象在运行时可以改变自身行为,而不必借助单一庞大的条件判断语句

以前在做一个商城中的订单时,设计的订单类大致意思如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class Order
{
private $state;

const UN_PAY_STATE = 0;

const PAY_STATE = 1;

const EVALUATE_STATE = 2;

const FINISH_STATE = 3;


public function handle()
{
switch ($this->state) {
case self::UN_PAY_STATE:
//客户新建订单,是未付款
break;
case self::PAY_STATE:
//客户未付款,要收钱
break;
case self::EVALUATE_STATE:
//客户已付款,要评价
break;
case self::FINISH_STATE:
//客户已评价,订单完成
break;
}
}
}

单独状态单独处理,手动设置状态,非常僵硬:

1
2
3
$order = new Order();
$order->setState(Order::PAY_STATE);
$order->handle();

下面用状态模式替代,已付款状态的例子:

State 接口规定了 doAction(Order $order)

PayState.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class PayState implements State
{
const STATE = 1;

public function doAction(Order $order)
{
if (self::STATE === $order->getCurrentState()) {
//调用API收钱
} else {
//转向下一个评价状态
$order->setState(new EvaluateState());
$order->handle();
}
}
}

原来的订单类中需要加上新属性: $currentState,存放当前状态

而原来的 $state 属性存放的就不是值了,而是一个状态对象:

Order.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Order
{
private $state;
private $currentState;

public function __construct()
{
$this->state = new UnPayState();
$this->currentState = UnPayState::STATE;
}

public function handle()
{
$this->state->doAction($this);
}
}