状态模式的应用
前景:
xx公司要启动一个项目,这个项目的需求是合同协议管理,需求分别为:
1. 合作的过程中创建一份协议。
2. 协议开始的过程中可以暂停和恢复。
3. 当然合作可以延长合作时间和提前结束,不管哪一种都要算服务天数,因为费用是按天计算的。
4. 财务可以看到本月实际的营业额。
接到需求之后就有人开始编码了(这是国内的习惯):
协议创建的时候的合法性检测:
#检测是否存在合作中的协议 ..... $isCooperation = Agreement::model()->exists("nick=? and begin_date>=? and end_date<=?",array('xx',date(),date())); if($isCooperation){ throw new Exception("存在合作中的协议,无法新建"); } #检测是否有暂停的协议 $isExistsStop = Agreement::model()->exists("nick=? and status=?",array('xx','stop')); if($isExistsStop){ throw new Exception("存在暂停的协议,无法新建"); } ......
协议开始的时候的合法性检测:
#检测是否存在为开始状态的协议 $agreement = Agreement::model()->find("nick=? and status=? begin_date>=? and end_date<=?",array('xx','NotStart',date(),date())); if($agreement == null){ throw new Exception("未找到开始状态的订单"); } $agreement->start_date = date(); $agreement->status = 'Start'; $agreement->save(); ......
协议暂停的时候的合法性检测:
#同上
状态越来越多 的时候,我们就越来越麻木了,不知道当前的动作会转变成什么状态,前置状态是否合理。
解决这一问题,我们引进下设计模式这个概念,其实代码基础还是不会变,只是转成了另外一种表现形式。
状态模式解读:http://www.cnblogs.com/wangjq/archive/2012/07/16/2593485.html
1. 概述
当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类。
2. 解决的问题
主要解决的是当控制一个对象状态转换的条件表达式过于复杂时的情况。把状态的判断逻辑转移到表示不同的一系列类当中,可以把复杂的逻辑判断简单化。
3. 模式中的角色
3.1 上下文环境(Context):它定义了客户程序需要的接口并维护一个具体状态角色的实例,将与状态相关的操作委托给当前的Concrete State对象来处理。
3.2 抽象状态(State):定义一个接口以封装使用上下文环境的的一个特定状态相关的行为。
3.3 具体状态(Concrete State):实现抽象状态定义的接口。
我们从需求中分析下,提出动词:
1. 开始 (Start)
2. 暂停 (Pause)
3. 恢复 (Resume)
4. 终止 (Over)
5. 续约 (Review)
根据状态,我们列出以下状态:
1. 未开始(NotStart)
2. 服务中 (Start)
3. 暂停服务 (Pause)
4. 服务结束 (Over)
我们在来列一份表格
未开始 | 服务中 | 暂停服务 | 服务结束 | |
开始 | 服务中 | error | error | error |
暂停 | error | 暂停服务 | error | error |
恢复 | error | error | 服务中 | error |
终止 | 服务结束 | 服务结束 | 服务结束 | 服务结束 |
续约 | 未开始 | 服务中 | error | 未开始/服务中 |
这份表格代表着状态的转化过程。
我们根据状态模式的定义来化出类图结构:
代码如下(仅供参考):
<?php class AgreementContext { /** * @var AgreementState */ private $state; public $agreement; public function setState($state){ $this->state = $state; } public function start(){ $this->state->start($this); } public function pause(){ $this->state->pause($this); } public function resume(){ $this->state->resume($this); } public function over(){ $this->state->over($this); } } abstract class AgreementState { public function start($context); public function pause($context); public function resume($context); public function over($context); } class AgreementNotStartState extends AgreementState { public function start($context){ if($context->agreement->begin_time >= time() && $context->agreement->end_time<=time()){ $context->agreement->startDate = date(); $context->state = new AgreementServiceState(); } } public function pause($context){ throw new Exception("The state is no service ,can not switch to pause", 1); } public function resume($context){ throw new Exception("The state is no service ,can not switch to resume", 1); } public function over($context){ $context->agreement->overDate = date(); $context->state = new AgreementOverState(); } } class AgreementServiceState extends AgreementState { public function start($context){ throw new Exception("...", 1); } public function pause($context){ if($context->agreement->begin_time >= time() && $context->agreement->begin_time<=time()){ $context->agreement->stopDate = date(); $context->state = new AgreementPauseState(); } } public function resume($context){ throw new Exception("...", 1); } public function over($context){ $context->agreement->overDate = date(); $context->state = new AgreementOverState(); } } class AgreementPauseState extends AgreementState { .... public function resume($context){ $context->agreement->resumeDate = date(); $context->state = new AgreementServiceState(); } public function over($context){ $context->agreement->overDate = date(); $context->state = new AgreementOverState(); } .... } class AgreementOverState extends AgreementState { ... }
出处:http://www.cnblogs.com/oshine/
本作品由oShine.Q 创作, 欢迎转载,但任何转载必须保留完整文章,在显要地方显示署名以及原文链接。如您有任何疑问,请给我留言。