状态模式(State)

目的

状态模式可以基于一个对象的同种事务而封装出不同的行为。它提供一种简洁的方式使得对象在运行时可以改变自身行为,而不必借助单一庞大的条件判断语句。

UML 类图

file

代码

你可以在 GitHub 上找到这些代码

ContextOrder.php

  1. <?php
  2. namespace DesignPatterns\Behavioral\State;
  3. class ContextOrder extends StateOrder
  4. {
  5. public function getState():StateOrder
  6. {
  7. return static::$state;
  8. }
  9. public function setState(StateOrder $state)
  10. {
  11. static::$state = $state;
  12. }
  13. public function done()
  14. {
  15. static::$state->done();
  16. }
  17. public function getStatus(): string
  18. {
  19. return static::$state->getStatus();
  20. }
  21. }

StateOrder.php

  1. <?php
  2. namespace DesignPatterns\Behavioral\State;
  3. abstract class StateOrder
  4. {
  5. /**
  6. * @var array
  7. */
  8. private $details;
  9. /**
  10. * @var StateOrder $state
  11. */
  12. protected static $state;
  13. /**
  14. * @return mixed
  15. */
  16. abstract protected function done();
  17. protected function setStatus(string $status)
  18. {
  19. $this->details['status'] = $status;
  20. $this->details['updatedTime'] = time();
  21. }
  22. protected function getStatus(): string
  23. {
  24. return $this->details['status'];
  25. }
  26. }

ShippingOrder.php

  1. <?php
  2. namespace DesignPatterns\Behavioral\State;
  3. class ShippingOrder extends StateOrder
  4. {
  5. public function __construct()
  6. {
  7. $this->setStatus('shipping');
  8. }
  9. protected function done()
  10. {
  11. $this->setStatus('completed');
  12. }
  13. }

CreateOrder.php

  1. <?php
  2. namespace DesignPatterns\Behavioral\State;
  3. class CreateOrder extends StateOrder
  4. {
  5. public function __construct()
  6. {
  7. $this->setStatus('created');
  8. }
  9. protected function done()
  10. {
  11. static::$state = new ShippingOrder();
  12. }
  13. }

测试

Tests/StateTest.php

  1. <?php
  2. namespace DesignPatterns\Behavioral\State\Tests;
  3. use DesignPatterns\Behavioral\State\ContextOrder;
  4. use DesignPatterns\Behavioral\State\CreateOrder;
  5. use DesignPatterns\Behavioral\State\ShippingOrder;
  6. use PHPUnit\Framework\TestCase;
  7. class StateTest extends TestCase
  8. {
  9. public function testCanShipCreatedOrder()
  10. {
  11. $order = new CreateOrder();
  12. $contextOrder = new ContextOrder();
  13. $contextOrder->setState($order);
  14. $contextOrder->done();
  15. $this->assertEquals('shipping', $contextOrder->getStatus());
  16. }
  17. public function testCanCompleteShippedOrder()
  18. {
  19. $order = new ShippingOrder();
  20. $contextOrder = new ContextOrder();
  21. $contextOrder->setState($order);
  22. $contextOrder->done();
  23. $this->assertEquals('completed', $contextOrder->getStatus());
  24. }
  25. }