首页/Home PHP Design Patterns 状态模式(State Pattern)

状态模式(State Pattern)

PrintE-mail
Wednesday, 16 December 2009 18:38   Review this article  Add to Technorati Favorites

下面以糖果机为例进行讲解。

分析&设计

糖果机的状态可分为四种: 没有硬币、有硬币、糖果售出、糖果售馨。
糖果机可执行的动作也可分为四种:插入硬币、弹出硬币、转动曲柄、发放糖果。

糖果机状态图如下:

 

糖果机状态图

相应地,其类图如下 (接口中所含四种方法已省略):

糖果机类图

所需接口:状态。

所需类有:糖果机,售出状态,售馨状态,无硬币状态,有硬币状态。

实现

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 ) {
        
$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 ) {
            
$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 ) {
            
$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() > ) {
            
$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

 

 

回复

留个脚印儿吧.


回复

Copyright © 2010 PHP 架构. All Rights Reserved.