助力软件开发企业降本增效 PHP / java源码系统,只需一次付费,代码终身使用! 广告
## 状态模式的定义与特点 状态(State)模式的定义:对有状态的对象(对象可能会根据不同的情况做出不同的行为),把复杂的“判断逻辑”提取到不同的状态对象中,允许状态对象在其内部状态发生改变时改变其行为。 **优点:** 1. 状态模式将与特定状态相关的行为局部化到一个状态中,并且将不同状态的行为分割开来,满足“单一职责原则”。 2. 减少对象间的相互依赖。将不同的状态引入独立的对象中会使得状态转换变得更加明确,且减少对象间的相互依赖。 3. 避免if语句有利于程序的扩展。通过定义新的子类很容易地增加新的状态和转换。 **缺点:** 1. 增加系统的类与对象的个数。 2. 状态模式的结构与实现都较为复杂,如果使用不当会导致程序结构和代码的混乱。 ## **状态模式的结构** 状态模式把受环境改变的对象行为包装在不同的状态对象里,其意图是让一个对象在其内部状态改变的时候,其行为也随之改变。现在我们来分析其基本结构和实现方法。 ## **应用场景:** * 用于对象的不同功能的转换 * 当一个对象的行为取决于它的状态,并且它必须在运行时根据状态改变它的行为时,就可以考虑使用状态模式。 * 一个操作中含有庞大的分支结构,并且这些分支决定于对象的状态时。 ## **模式的结构** 1. 环境(Context)角色:也称为上下文,它定义了客户感兴趣的接口,维护一个当前状态,并将与状态相关的操作委托给当前状态对象来处理。 2. 抽象状态(State)角色:定义一个接口,用以封装环境对象中的特定状态所对应的行为。 3. 具体状态(Concrete    State)角色:实现抽象状态所对应的行为。 其结构图如图所示 ![](https://img.kancloud.cn/58/a2/58a20e5abd0c583f85b5bcb5b21ca9d7_605x350.png) ``` //环境类 class Context { private $state; //定义环境类的初始状态 public function __construct() { $this->state = new ConcreteStateA(); } //设置新状态 public function setState(State $state) { $this->state = $state; } /** * 读取状态 * @return State */ public function getState() { return $this->state; } //对请求做处理 public function Handle() { $this->state->Handle($this); } } //抽象状态类 abstract class State { abstract public function Handle(Context $context); } //具体状态A类 class ConcreteStateA extends State { public function Handle(Context $context) { print_r("当前状态是 A."); $context->setState(new ConcreteStateB()); } } //具体状态B类 class ConcreteStateB extends State { public function Handle(Context $context) { print_r("当前状态是 B."); $context->setState(new ConcreteStateA()); } } class Client { public static function main() { $context = new Context(); //创建环境 $context->Handle(); //处理请求 $context->Handle(); $context->Handle(); $context->Handle(); } } Client::main(); 结果: 当前状态是 A.当前状态是 B.当前状态是 A.当前状态是 B. ``` 不用状态模式时用if判断 ``` //环境类 class Context { private $state; //定义环境类的初始状态 public function __construct() { $this->state = 1; } //设置新状态 public function setState(int $state) { $this->state = $state; } /** * 读取状态 * @return State */ public function getState() { return $this->state; } //对请求做处理 public function Handle() { if ($this->state == 1) { echo "状态A"; } else if ($this->state == 2) { echo "状态B"; } } } ``` 例子: ``` //环境类 class ScoreContext { private $state; //AbstractState public function __construct() { $this->state = new LowState($this); } public function setState(AbstractState $state) { $this->state = $state; } /** * @return AbstractState */ public function getState() { return $this->state; } public function add(int $score) { $this->state->addScore($score); } } //抽象状态类 abstract class AbstractState { protected $scoreContext; //环境 ScoreContext protected $stateName = ""; //状态名 protected $score = 0; //分数 abstract public function checkState(); //检查当前状态 public function addScore(int $x) { //设置当前分数 $this->score += $x; echo "加上:".$x."分,\t当前分数:".$this->score."分,"; echo $this->score; //更具当前分数设置状态 $this->checkState(); print_r("\t当前状态:".$this->scoreContext->getState()->stateName."<br>"); } } //具体状态类:不及格 注意这里的参数是ScoreContext而其他的是AbstractState class LowState extends AbstractState { public function __construct($h) { if ($h instanceof ScoreContext) { $this->scoreContext = $h; $this->stateName = "不及格"; $this->score = 0; }else if ($h instanceof AbstractState) { $this->scoreContext = $h->scoreContext; $this->stateName = "不及格"; $this->score = $h->score; } } public function checkState() { if ($this->score >= 90) { $this->scoreContext->setState(new HighState($this)); } else if ($this->score >= 60) { $this->scoreContext->setState(new MiddleState($this)); } } } //具体状态类:中等 class MiddleState extends AbstractState { public function __construct(AbstractState $state) { $this->scoreContext = $state->scoreContext; $this->stateName = "中等"; $this->score = $state->score; } public function checkState() { if ($this->score < 60) { $this->scoreContext->setState(new LowState($this)); } else if ($this->score >= 90) { $this->scoreContext->setState(new HighState($this)); } } } //具体状态类:优秀 class HighState extends AbstractState { public function __construct(AbstractState $state) { $this->scoreContext = $state->scoreContext; $this->stateName = "优秀"; $this->score = $state->score; } public function checkState() { if ($this->score < 60) { $this->scoreContext->setState(new LowState($this)); } else if ($this->score < 90) { $this->scoreContext->setState(new MiddleState($this)); } } } class ScoreStateTest { public static function main() { $coreContext = new ScoreContext(); print_r("学生成绩状态测试:<br>"); $coreContext->add(30); $coreContext->add(40); $coreContext->add(25); $coreContext->add(-15); $coreContext->add(-25); } } ScoreStateTest::main(); 结果 学生成绩状态测试: 加上:30分, 当前分数:30分,30 当前状态:不及格 加上:40分, 当前分数:70分,70 当前状态:中等 加上:25分, 当前分数:95分,95 当前状态:优秀 加上:-15分, 当前分数:80分,80 当前状态:中等 加上:-25分, 当前分数:55分,55 当前状态:不及格 ``` 例子2: >[info] 未使用状态模式 ``` abstract class ILift { //电梯的四个状态 const OPENING_STATE = 1; //门敞状态 const CLOSING_STATE = 2; //门闭状态 const RUNNING_STATE = 3; //运行状态 const STOPPING_STATE = 4; //停止状态; //设置电梯的状态 public abstract function setState($state); //首先电梯门开启动作 public abstract function open(); //电梯门有开启,那当然也就有关闭了 public abstract function close(); //电梯要能上能下,跑起来 public abstract function run(); //电梯还要能停下来 public abstract function stop(); } /** * 电梯的实现类 */ class Lift extends ILift { private $state; public function setState($state) { $this->state = $state; } //电梯门关闭 public function close() { //电梯在什么状态下才能关闭 switch ($this->state) { case ILift::OPENING_STATE: //如果是则可以关门,同时修改电梯状态 $this->setState(ILift::CLOSING_STATE); break; case ILift::CLOSING_STATE: //如果电梯就是关门状态,则什么都不做 //do nothing; return ; break; case ILift::RUNNING_STATE: //如果是正在运行,门本来就是关闭的,也说明都不做 //do nothing; return ; break; case ILift::STOPPING_STATE: //如果是停止状态,本也是关闭的,什么也不做 //do nothing; return ; break; } echo 'Lift colse <br>'; } //电梯门开启 public function open() { //电梯在什么状态才能开启 switch($this->state){ case ILift::OPENING_STATE: //如果已经在门敞状态,则什么都不做 //do nothing; return ; break; case ILift::CLOSING_STATE: //如是电梯时关闭状态,则可以开启 $this->setState(ILift::OPENING_STATE); break; case ILift::RUNNING_STATE: //正在运行状态,则不能开门,什么都不做 //do nothing; return ; break; case ILift::STOPPING_STATE: //停止状态,淡然要开门了 $this->setState(ILift::OPENING_STATE); break; } echo 'Lift open <br>'; } //电梯开始跑起来 public function run() { switch($this->state){ case ILift::OPENING_STATE: //如果已经在门敞状态,则不你能运行,什么都不做 //do nothing; return ; break; case ILift::CLOSING_STATE: //如是电梯时关闭状态,则可以运行 $this->setState(ILift::RUNNING_STATE); break; case ILift::RUNNING_STATE: //正在运行状态,则什么都不做 //do nothing; return ; break; case ILift::STOPPING_STATE: //停止状态,可以运行 $this->setState(ILift::RUNNING_STATE); } echo 'Lift run <br>'; } //电梯停止 public function stop() { switch($this->state){ case ILift::OPENING_STATE: //如果已经在门敞状态,那肯定要先停下来的,什么都不做 //do nothing; return ; break; case ILift::CLOSING_STATE: //如是电梯时关闭状态,则当然可以停止了 $this->setState(ILift::CLOSING_STATE); break; case ILift::RUNNING_STATE: //正在运行状态,有运行当然那也就有停止了 $this->setState(ILift::CLOSING_STATE); break; case ILift::STOPPING_STATE: //停止状态,什么都不做 //do nothing; return ; break; } echo 'Lift stop <br>'; } } class Client { public static function test() { $lift = new Lift(); //电梯的初始条件应该是停止状态 $lift->setState(ILift::STOPPING_STATE); //首先是电梯门开启,人进去 $lift->open(); //然后电梯门关闭 $lift->close(); //再然后,电梯跑起来,向上或者向下 $lift->run(); //最后到达目的地,电梯挺下来 $lift->stop(); } } Client::test(); ``` 【例3】用“状态模式”设计一个多线程的状态转换程序。 分析:多线程存在 5 种状态,分别为新建状态、就绪状态、运行状态、阻塞状态和死亡状态,各个状态当遇到相关方法调用或事件触发时会转换到其他状态 ![](https://img.kancloud.cn/3b/c9/3bc9b23c3c175e27eafafbb01a67995a_609x164.png) 现在先定义一个抽象状态类(TheadState),然后为图 3 所示的每个状态设计一个具体状态类,它们是新建状态(New)、就绪状态(Runnable )、运行状态(Running)、阻塞状态(Blocked)和死亡状态(Dead),每个状态中有触发它们转变状态的方法,环境类(ThreadContext)中先生成一个初始状态(New),并提供相关触发方法 ![](https://img.kancloud.cn/6b/bf/6bbf8dddc11ac2a62adcecf5841f8216_629x670.png) ``` //环境类 class ThreadContext { private $state;//ThreadState public function __construct() { $this->state=new _New(); } public function setState(ThreadState $state) { $this->state=$state; } /** * * @return ThreadState */ public function getState() { return $this->state; } //新建状态 public function start() { $this->state->start($this); } //就绪状态 获取cpu时间 public function getCPU() { $this->state->getCPU($this);//Runnable } //运行状态 suspend 阻塞 public function suspend() { $this->state->suspend($this);//Running } //运行状态 结束 public function stop() { $this->state->stop($this);//Running } //阻塞状态 恢复 public function resume() { $this->state->resume($this);//Blocked } } //抽象状态类:线程状态 abstract class ThreadState { protected $stateName=""; //状态名 } //具体状态类:新建状态 class _New extends ThreadState { public function __construct() { $this->stateName="新建状态"; print_r("当前线程处于:新建状态."); } public function start(ThreadContext $hj) { print_r("调用start()方法-->"); if($this->stateName === "新建状态"){ $hj->setState(new Runnable()); }else{ print_r("当前线程不是新建状态,不能调用start()方法."); } } } //具体状态类:就绪状态 class Runnable extends ThreadState { public function __construct() { $this->stateName="就绪状态"; print_r("当前线程处于:就绪状态."); } public function getCPU(ThreadContext $hj) { print_r("获得CPU时间-->"); if($this->stateName==="就绪状态") { $hj->setState(new Running()); } else { print_r("当前线程不是就绪状态,不能获取CPU."); } } } //具体状态类:运行状态 class Running extends ThreadState { public function __construct() { $this->stateName="运行状态"; print_r("当前线程处于:运行状态."); } public function suspend(ThreadContext $hj) { print_r("调用suspend()方法-->"); if($this->stateName === "运行状态") { $hj->setState(new Blocked()); } else { print_r("当前线程不是运行状态,不能调用suspend()方法."); } } public function stop(ThreadContext $hj) { print_r("调用stop()方法-->"); if($this->stateName === "运行状态") { $hj->setState(new Dead()); } else { print_r("当前线程不是运行状态,不能调用stop()方法."); } } } //具体状态类:阻塞状态 class Blocked extends ThreadState { public function __construct() { $this->stateName="阻塞状态"; print_r("当前线程处于:阻塞状态."); } public function resume(ThreadContext $hj) { print_r("调用resume()方法-->"); if($this->stateName === "阻塞状态") { $hj->setState(new Runnable()); } else { print_r("当前线程不是阻塞状态,不能调用resume()方法."); } } } //具体状态类:死亡状态 class Dead extends ThreadState { public function __construct() { $this->stateName="死亡状态"; print_r("当前线程处于:死亡状态."); } } class ThreadStateTest { public static function main() { $context=new ThreadContext(); $context->start(); $context->getCPU(); $context->suspend(); $context->resume(); $context->getCPU(); $context->stop(); } ThreadStateTest::main(); 结果: 当前线程处于:新建状态. 调用start()方法-->当前线程处于:就绪状态. 获得CPU时间-->当前线程处于:运行状态. 调用suspend()方法-->当前线程处于:阻塞状态. 调用resume()方法-->当前线程处于:就绪状态. 获得CPU时间-->当前线程处于:运行状态. 调用stop()方法-->当前线程处于:死亡状态. ``` ## **状态模式的扩展** 在有些情况下,可能有多个环境对象需要共享一组状态,这时需要引入享元模式,将这些具体状态对象放在集合中供程序共享,其结构图如图所示 ![](https://img.kancloud.cn/04/c6/04c6541d9b75a8b91543c1f8b20d2c10_771x365.png) ``` //环境类 class ShareContext { private $state;//ShareState private $stateSet=array(); public function __construct() { $this->state=new ConcreteState1(); $this->stateSet["1"]=$this->state; $this->state=new ConcreteState2(); $this->stateSet["2"]=$this->state; $this->state=$this->getState("1"); } //设置新状态 public function setState(ShareState $state) { $this->state=$state; } /** * 读取状态 * @param String $key [description] * @return ShareState */ public function getState(String $key) { $s=$this->stateSet[$key]; return $s; } //对请求做处理 public function Handle() { $this->state->Handle($this); } } //抽象状态类 abstract class ShareState { public abstract function Handle(ShareContext $context); } //具体状态1类 class ConcreteState1 extends ShareState { public function Handle(ShareContext $context) { print_r("当前状态是: 状态1"); $context->setState($context->getState("2")); } } //具体状态2类 class ConcreteState2 extends ShareState { public function Handle(ShareContext $context) { print_r("当前状态是: 状态2"); $context->setState($context->getState("1")); } } class FlyweightStatePattern { public static function main() { $context=new ShareContext(); //创建环境 $context->Handle(); //处理请求 $context->Handle(); $context->Handle(); $context->Handle(); } } FlyweightStatePattern::main(); ```