状态模式

定义

状态模式(State Pattern)允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它的类。

状态模式通用类图

image

State——抽象状态角色

接口或抽象类,负责对象状态定义,并且封装环境角色以实现状态切换。

ConcreteState——具体状态角色

每一个具体状态必须完成两个职责:本状态的行为管理以及趋向状态处理,通俗地说,就是本状态下要做的事情,以及本状态如何过渡到其他状态。

Context——环境角色

定义客户端需要的接口,并且负责具体状态的切换。

状态模式的优点:

结构清晰,避免了过的switch…case或者if…else语句的使用,避免了程序的复杂性,提供系统的可维护性。实质上状态模式所做的,就是将与特定状态相关的行为局部化,并且将不同状态的行为分割开来。State将特定的状态行为都放入一个对象中,由于所有与状态相关的代码都存在于某一个ConcreteState类中, 所以通过定义新的子类可以很容易的增加新的状态和转换[DP]

缺点:

其实增加新的子类并不容易,因为在状态对象中,只定义了向下一状态转换的接口函数,而并不知道其可以由哪些状态转换来,所以,添加新的状态子类时,转至下一状态的功能好实现,但转来的功能就不好实现了,需要去逐个修改可以转换至该状态的所有状态以添加转换至此的功能。导致这一问题的原因是,各状态子类之间的相互转换是各自独立实现的,这其实增加了状态子类之间的耦合度。

举例:

来自《大话设计模式》以电梯为例,其有四个状态:运行,停止,开门,关门,相互之间转换关系如图:

image

C++实现,部分细节与《大话设计模式》中的java实现不同

#include <iostream>

using namespace std;
class Lift;
class LiftState{    //定义抽象状态角色
protected:
    Lift *lift;   //定义环境角色(这里是电梯),封装状态的变化引起的功能变化
protected:
    void SetContext(Lift *lift){this->lift = lift;};

    //实现功能或进行状态切换的函数声明
    virtual void open(){};
    virtual void close(){};
    virtual void run(){};
    virtual void stop(){};

    friend class Lift;
};

class Lift{     //环境角色
private:    //隐藏状态对象
    static LiftState * const statesSet[];   //指针数组
    LiftState *liftstate;   //当前电梯状态
public:
    enum STATETYPE{OPENING,CLOSING,RUNNING,STOPPING};   //此处枚举类型的值顺序应该与statesSet的初始化顺序对应
public:
    void setLiftState(STATETYPE state)
    {
        this->liftstate=statesSet[state];   //由枚举类型映射到
        this->liftstate->SetContext(this);
    }
    void open(){
        this->liftstate->open();
    }
    void close(){
        this->liftstate->close();
    }
    void run(){
        this->liftstate->run();
    }
    void stop(){
        this->liftstate->stop();
    }
};

class OpeningState:public LiftState{

public:
    void open(){       //当前状态下的核心任务
        cout<<"电梯门开启..."<<endl;
    }
    void close(){   //可切换到的下一个状态
        lift->setLiftState(lift->CLOSING);  //先切换状态
        lift->close();      //再执行动作
    }
    //开门状态下是不能运行也不需要停止的,所以这两个功能就使用基类里的默认实现了,即什么也不做
    //什么也不做是一种消极的处理,有时候可能需要返回提示信息以告诉用户操作错误,或者做些其他处理。
};
class ClosingState:public LiftState{
public:
    void close(){
        cout<<"电梯门关闭..."<<endl;
    }
    void open(){
        lift->setLiftState(lift->OPENING);  //先切换状态
        lift->open();       //再执行动作
    }
    void run(){
        lift->setLiftState(lift->RUNNING);
        lift->run();
    }
    void stop(){
        lift->setLiftState(lift->STOPPING);
        lift->stop();
    }
};
class RunningState:public LiftState{
public:
    void run(){
        cout<<"电梯上下运行..."<<endl;
    }
    void stop(){
        lift->setLiftState(lift->STOPPING);
        lift->stop();
    }
};
class StoppingState:public LiftState{
    void stop(){
        cout<<"电梯停止了..."<<endl;
    }
    void open(){
        lift->setLiftState(lift->OPENING);  //先切换状态
        lift->open();       //再执行动作
    }
    void run(){
        lift->setLiftState(lift->RUNNING);
        lift->run();
    }
};
LiftState * const Lift::statesSet[]={new OpeningState,new ClosingState,new RunningState,new StoppingState};

int main()
{
    Lift lift;
    lift.setLiftState(lift.CLOSING);
    lift.open();
    lift.close();
    lift.run();
    lift.stop();
    return 0;
}

运行结果:

image

posted @ 2014-06-18 21:48  星辰风  阅读(351)  评论(0编辑  收藏  举报