|
下面以糖果机为例进行讲解。 分析&设计
糖果机的状态可分为四种: 没有硬币、有硬币、糖果售出、糖果售馨。 糖果机可执行的动作也可分为四种:插入硬币、弹出硬币、转动曲柄、发放糖果。 糖果机状态图如下:
相应地,其类图如下 (接口中所含四种方法已省略):
所需接口:状态。 所需类有:糖果机,售出状态,售馨状态,无硬币状态,有硬币状态。 实现
1. 状态接口
interface State { public function insertCoin(); public function ejectCoin(); public function turnCrank(); public function dispense(); } 2. 糖果机类
class GumballMachine { private $soldOutState; private $noCoinState; private $hasCoinState; private $soldState;
private $state; private $count = 0;
public function __construct ( $numGumballs = 0 ) { $this->soldOutState = new SoldOutState($this); $this->noCoinState = new NoCoinState($this); $this->hasCoinState = new HasCoinState($this); $this->soldState = new SoldState($this);
$this->count = $numGumballs; if ( $numGumballs > 0 ) { $this->state = $this->noCoinState; } else { $this->state = $this->soldOutState; } }
public function insertCoin () { $this->state->insertCoin(); }
public function ejectCoin () { $this->state->ejectCoin(); }
public function turnCrank () { $this->state->turnCrank(); $this->state->dispense(); }
public function setState ( $state ) { $this->state = $state; }
public function releaseBall () { echo "还有糖果{$this->count}. 将有糖果滚出...\n"; if ( $this->count > 0 ) { $this->count = $this->count - 1; } }
public function getNoCoinState () { return $this->noCoinState; }
public function getHasCoinState () { return $this->hasCoinState; }
public function getSoldOutState () { return $this->soldOutState; }
public function getSoldState () { return $this->soldState; }
public function getCount () { return $this->count; } } 3. 售出状态类
class SoldState implements State { private $machine;
public function __construct ( $machine ) { $this->machine = $machine; }
public function insertCoin () { echo "请稍等, 我们已经给了你一个糖果.\n"; }
public function ejectCoin () { echo "抱歉, 你已经转动了曲柄.\n"; }
public function turnCrank () { echo "转两次也不会给你两个糖果.\n"; }
public function dispense () { $this->machine->releaseBall(); if ( $this->machine->getCount() > 0 ) { $this->machine->setState( $this->machine->getNoCoinState() ); } else { echo "没有糖果了.\n"; $this->machine->setState( $this->machine->getSoldOutState() ); } } } 4. 售馨状态类class SoldOutState implements State { private $machine;
public function __construct ( $machine ) { $this->machine = $machine; }
public function insertCoin () { echo "糖果已经没了. 别插硬币了.\n"; }
public function ejectCoin () { echo "你还没插入硬币呢.\n"; }
public function turnCrank () { echo "没有糖果了. 转动曲柄也没用.\n"; }
public function dispense () { echo "没有糖果可发放\n"; } } 5. 无硬币状态类class NoCoinState implements State { private $machine;
public function __construct ( $machine ) { $this->machine = $machine; }
public function insertCoin () { echo "你插入了硬币.\n"; $this->machine->setState( $this->machine->getHasCoinState() ); }
public function ejectCoin () { echo "你还没插硬币呢.\n"; }
public function turnCrank () { echo "你转动了曲柄, 但没有硬币.\n"; }
public function dispense () { echo "你得先插入硬币.\n"; } } 6. 有硬币状态类class HasCoinState implements State { private $machine;
public function __construct ( $machine ) { $this->machine = $machine; }
public function insertCoin () { echo "已经有硬币了. 别再投了.\n"; }
public function ejectCoin () { echo "硬币已弹出.\n"; $this->machine->setState( $this->machine->getNoCoinState() ); }
public function turnCrank () { echo "你转动了曲柄.\n"; $this->machine->setState( $this->machine->getSoldState() ); }
public function dispense () { echo '没有糖果弹出.'; } } 测试用例
$m = new GumballMachine(7); $m->insertCoin(); $m->turnCrank(); $m->ejectCoin(); echo '剩余糖果: '. $m->getCount() ."\n\n";
$m->insertCoin(); $m->turnCrank(); echo '剩余糖果: '. $m->getCount() ."\n\n";
$m->insertCoin(); $m->ejectCoin(); $m->turnCrank(); echo '剩余糖果: '. $m->getCount() ."\n\n";
$m->insertCoin(); $m->turnCrank(); echo '剩余糖果: '. $m->getCount() ."\n\n";
$m->insertCoin(); $m->insertCoin(); $m->turnCrank(); echo '剩余糖果: '. $m->getCount() ."\n"; 测试结果你插入了硬币. 你转动了曲柄. 将有糖果滚出... 你还没插硬币呢. 剩余糖果: 6
你插入了硬币. 你转动了曲柄. 将有糖果滚出... 剩余糖果: 5
你插入了硬币. 硬币已弹出. 你转动了曲柄, 但没有硬币. 你得先插入硬币. 剩余糖果: 5
你插入了硬币. 你转动了曲柄. 将有糖果滚出... 剩余糖果: 4
你插入了硬币. 已经有硬币了. 别再投了. 你转动了曲柄. 将有糖果滚出... 剩余糖果: 3
|