定义:
状态模式(State):当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类。
结构:
- State:抽象状态类,定义一个接口以封装与 Context 的一个特定状态相关的行为。
- Context:环境类,维护一个 ConcreteState 子类的实例,这个实例定义当前的状态。
- ConcreteState:具体状态类,每一个子类实现一个与 Context 的一个状态相关的行为。
- Client:客户端代码。
代码实例:
/** * 抽象状态类 * Class State */ abstract class State { /** * 封装一个与状态相关的行为,由子类具体实现 * @param Context $context */ abstract public function handle(Context $context); } /** * 具体状态类A * Class ConcreteStateA */ class ConcreteStateA extends State { /** * 实现状态A相关行为并指定下一状态 * @param Context $context */ public function handle(Context $context) { // TODO: Implement handle() method. echo "现在是状态A<br/>"; // 指定下一状态为状态B $context->setState(new ConcreteStateB()); } } /** * 具体状态类B * Class ConcreteStateB */ class ConcreteStateB extends State { /** * 实现状态B相关行为并指定下一状态 * @param Context $context */ public function handle(Context $context) { // TODO: Implement handle() method. echo "现在是状态B<br/>"; // 指定下一状态为状态C $context->setState(new ConcreteStateC()); } } /** * 具体状态类C * Class ConcreteStateC */ class ConcreteStateC extends State { /** * 实现状态C相关行为 * @param Context $context */ public function handle(Context $context) { // TODO: Implement handle() method. echo "现在是状态C,结束<br/>"; } } /** * 环境类 * Class Context */ class Context { /** * 保存State对象 */ private $state; /** * 设置当前状态 * @param State $state */ public function setState(State $state) { $this->state = $state; } /** * 请求状态相关行为 */ public function request() { $this->state->handle($this); } } // 客户端调用 $context = new Context(); // 初始化设置状态为A $context->setState(new ConcreteStateA()); $context->request(); $context->request(); $context->request(); // 结果 现在是状态A 现在是状态B 现在是状态C,结束
再来一个商城根据会员积分打折的的实例:
/** * 抽象状态类 * Class State */ abstract class State { /** * 封装一个与状态相关的行为,由子类具体实现 * @param Member $member */ abstract public function handle(Member $member); } /** * 钻石会员 */ class DiamondsState extends State { public function handle(Member $member) { // TODO: Implement handle() method. if ($member->getIntegral() >= 2000) { echo "当前会员等级为钻石,等级积分为:{$member->getIntegral()},折扣为:0.7<br/>"; return 0.7; } else { // 大于2000积分0.7折,不满足走下一状态 $member->setState(new GoldState()); return $member->request(); } } } /** * 黄金会员 */ class GoldState extends State { public function handle(Member $member) { // TODO: Implement handle() method. if ($member->getIntegral() >= 1000) { echo "当前会员等级为黄金,等级积分为:{$member->getIntegral()},折扣为:0.8<br/>"; return 0.8; } else { // 大于1000积分0.8折,不满足走下一状态 $member->setState(new SilverState()); return $member->request(); } } } /** * 白银会员 */ class SilverState extends State { public function handle(Member $member) { // TODO: Implement handle() method. if ($member->getIntegral() >= 500) { echo "当前会员等级为白银,等级积分为:{$member->getIntegral()},折扣为:0.9<br/>"; return 0.9; } else { // 大于500积分0.9折,不满足则没有折扣 return 1; } } } /** * 会员用户 * Class Member */ class Member { /** * 保存State对象 */ private $state; /** * 积分 */ private $integral; /** * 设置当前状态 * @param State $state */ public function setState(State $state) { $this->state = $state; } /** * 设置积分 * @param $integral */ public function setIntegral($integral) { $this->integral = $integral; } /** * 获取积分 */ public function getIntegral() { return $this->integral; } /** * 请求状态相关行为 */ public function request() { return $this->state->handle($this); } } // 客户端调用 $member = new Member(); $member->setState(new DiamondsState()); $member->setIntegral(2500); $member->request(); $member->setIntegral(1200); $member->request(); $member->setIntegral(600); $member->request(); // 结果 当前会员等级为钻石,等级积分为:2500,折扣为:0.7 当前会员等级为黄金,等级积分为:1200,折扣为:0.8 当前会员等级为白银,等级积分为:600,折扣为:0.9
总结:
- 状态模式主要解决的是当控制一个对象状态转换的条件表达式过于复杂时的情况。把状态的判断逻辑转移到表示不同状态的一系列类当中,可以把复杂的判断逻辑简化。
- 状态模式的好处是将与特定状态相关的行为局部化,并且将不同状态的行为分割开来。可以消除庞大的条件分支语句,状态模式通过把各种状态转移逻辑分布到 State 的子类之间,来减少相互间的依赖。
- 当一个对象的行为取决于它的状态,并且它必须在运行时刻根据状态改变它的行为时,就可以考虑使用状态模式了。