最近,朋友一公司在开发一套OA系统。其中有一个设备管理的功能。设备采购后入库,然后分配,使用中可以维修,维修不成功就可以报废。这一系列的流程看似比较复杂。如果要用if和else来做各种操作的判断那会相当地复杂。于是,向开发人员推荐使用状态模式。首先,我们要理清楚。设备共有哪几种状态,哪几种操作?
操作有:入库,分配使用,维修,报废
状态有:待入库,已入库,待分配,使用中,维修中,已报废。
操作有:入库,分配使用,维修,报废
状态有:待入库,已入库,待分配,使用中,维修中,已报废。
那我们就建立一个抽象状态类,以及状态中可以拥有的各种操作.同时需要有一个变量指向我们这个状态是哪个设备的状态。初始化时需将此设备当参数传入。
abstract class State
{
//设备
prottected $_device;
//初始化时,将设备传入
public function __construct($device)
{
$this->_device = $device;
}
//入库
abstract public function storage();
//分配使用
abstract public function assign();
//维修
abstract public function repire();
//报废
abstract public function discard();
}
?>
同时,我们建立多个具体的State类。我们以待入库为例。待入库的状态,只能进行入库操作,所以在storage()方法中做入库操作,同时将设备的状态切换到已入库。而其它的操作均无效,直接填空即可。
class NewState extends State
{
public function storage()
{
echo "入库".PHP_EOL;
//入库完成后就切换成已入库状态。需要用到后面的Device类
$this->_device->setState(Device::STATE_STORAGED);
}
public function assign()
{
//不允许分配,什么都不做
}
public function repire()
{
//待入库状态,无需维修
}
public function discard()
{
//待入库状态,不能报废
}
}
其它的具体状态也要实现,分别为StoragedState, ReadyState, UsingState, RepireState, DiscardState。这里我们省略掉具体的实现代码。除了状态,我们还需要一个设备类。在设备类中,我们需要初始化所有有状态。并且提供一个设置状态的方法用来切换当前状态。同时,我们把需要的所有操作也放在Device类中,但委托给相应的状态类去完成。
class Device
{
//定义状态
const STATE_NEW = 'new';
const STATE_STORAGED = 'storaged';
const STATE_READY = 'ready';
const STATE_USING = 'using';
const STATE_REPIRE = 'repire';
const STATE_DISCARD = 'discard';
//可以有的状态
protected static $_allowState = array(
self::STATE_NEW,
self::STATE_STORAGED,
self::STATE_READY,
self::STATE_USING,
self::STATE_REPIRE,
self::STATE_DISCARD,
);
//表示当前的设备状态
protected $_state;
//初始化时,默认状态为待入库状态
public function __construct()
{
//初始化所有状态
foreach (self::$_allowState as $name) {
$name = "_{$name}State";
$className = ucfirst($name).'State';
$this->$name = new $className($this);
}
$this->_state = $this->_newState;
}
//设置当前的状态
public function setState($state)
{
$name = "_".$state."State";
$this->_state = $this->$name;
}
//入库
public function storage()
{
$this->_state->storage();
}
//分配
public function assign()
{
$this->_state->assign();
}
//维修
public function repire()
{
$this->_state->repire();
}
//报废
public function discard()
{
$this->_state->discard();
}
}
这样,一个状态机模式就实现了,在状态机模式中,把具体的业务逻辑都放在了状态类中进行处理,状态类实现每个操作的业务逻辑,并切换到新的状态。而此时,具有状态的实体就不用关心其操作逻辑和切换逻辑也不用利用大量的if和else来进行判断来实现业务。同时有兴趣的童鞋,可以把其它几个状态类的代码实现一下。