C++设计模式十三--StatePattern(状态模式)

来源:互联网 发布:室内设计在线设计软件 编辑:程序博客网 时间:2024/05/23 02:01

定义

  状态模式允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它的类。

要点

  1.状态模式允许一个对象基于内部状态而拥有不同的行为。
  2.和程序状态机(PSM)不同,状态模式用类代表状态。
  3.Context会将行为委托给当前状态对象。
  4.通过将每个状态封装进一个类,我们把以后需要做的任何改变局部化了。
  5.状态模式和策略模式有相同的类图,但它们的意图不同。
  6.策略模式通常会用行为或算法来配置Context类,而状态模式允许Context随着状态的改变而改变行为。
  7.状态可以有State类或者Context类控制。
  8.使用状态模式通常会导致设计中类的数目大量增加。
  9.状态类可以被多个Context示例共享。

类图

这里写图片描述

Context:它拥有一些内部状态。当有人调用request()方法时,它就会被委托到状态来处理(state->handle())。
State:状态接口,所有状态都需要实现这个接口,这样一来,状态之间可以互相替换。
ConcreteStateA/ConcreteStateB:具体状态,可以有很多。处理来自Context的请求。每个ConcreteState都提供了它自己对于请求的实现。所以当Context改变状态时行为也跟着改变。

示例

下面通过实现一个糖果自动售货机,其中状态图如下所示:
这里写图片描述

State.h

#ifndef STATE_H#define STATE_H#include <iostream>namespace StatePattern {using std::cout;using std::endl;class GumballMachine;class State {public:    State(){}    virtual ~State(){}    virtual void insertQuarter() = 0;    virtual void ejectQuarter() = 0;    virtual void turnCrank() = 0;    virtual void dispense() = 0;        };// 未投入硬币class NoQuarterState : public State {private:    GumballMachine* m_gumballMachine;public:    NoQuarterState(GumballMachine* gumballMachine);    virtual ~NoQuarterState();    void insertQuarter();    void ejectQuarter();    void turnCrank();    void dispense();};// 投入硬币class HasQuarterState : public State {private:    GumballMachine* m_gumballMachine;public:    HasQuarterState(GumballMachine* gumballMachine);    virtual ~HasQuarterState();    void insertQuarter();    void ejectQuarter();    void turnCrank();    void dispense();};// 准备出售糖果class SoldState : public State {private:    GumballMachine* m_gumballMachine;public:    SoldState(GumballMachine* gumballMachine);    virtual ~SoldState();    void insertQuarter();    void ejectQuarter();    void turnCrank();    void dispense();};// 糖果售罄class SoldOutState : public State {private:    GumballMachine* m_gumballMachine;public:    SoldOutState(GumballMachine* gumballMachine);    virtual ~SoldOutState();    void insertQuarter();    void ejectQuarter();    void turnCrank();    void dispense();};class WinnerState : public State {private:    GumballMachine* m_gumballMachine;public:    WinnerState(GumballMachine* gumballMachine);    virtual ~WinnerState();    void insertQuarter();    void ejectQuarter();    void turnCrank();    void dispense();};}#endif

State.cpp

#include "State.h"#include "GumballMachine.h"using namespace StatePattern;NoQuarterState::NoQuarterState(GumballMachine* gumballMachine){    this->m_gumballMachine = gumballMachine;}NoQuarterState::~NoQuarterState(){}void NoQuarterState::insertQuarter(){    cout << "You inserted a quarter" << endl;    m_gumballMachine->setState(m_gumballMachine->getHasQuarterState());}void NoQuarterState::ejectQuarter(){    cout << "You haven't inserted a quarter..." << endl;}void NoQuarterState::turnCrank(){    cout << "YOu turned, but there's no quarter" << endl;}void NoQuarterState::dispense(){    cout << "You need to pay first" << endl;}       HasQuarterState::HasQuarterState(GumballMachine* gumballMachine){    this->m_gumballMachine = gumballMachine;}HasQuarterState::~HasQuarterState(){}void HasQuarterState::insertQuarter(){    cout << "You can't insert another quarter" << endl;}void HasQuarterState::ejectQuarter(){    cout << "Quarter returned" << endl;    m_gumballMachine->setState(m_gumballMachine->getNoQuarterState());}void HasQuarterState::turnCrank(){    cout << "You turned..." << endl;    m_gumballMachine->setState(m_gumballMachine->getSoldState());}void HasQuarterState::dispense(){    cout << "No gumball dispensed" << endl;}   SoldState::SoldState(GumballMachine* gumballMachine){    this->m_gumballMachine = gumballMachine;}SoldState::~SoldState(){}void SoldState::insertQuarter(){    cout << "Please wait, we're already giving you a gumball" << endl;}void SoldState::ejectQuarter(){    cout << "Sorry, you alread turned the crank" << endl;}void SoldState::turnCrank(){    cout << "Turning twice doesn't get you another gumball" << endl;}void SoldState::dispense(){    m_gumballMachine->releaseBall();    if (m_gumballMachine->getCount() > 0) {        m_gumballMachine->setState(m_gumballMachine->getNoQuarterState());    } else {        cout << "Oops, out of gumballs" << endl;        m_gumballMachine->setState(m_gumballMachine->getSoldOutState());    }}   SoldOutState::SoldOutState(GumballMachine* gumballMachine){    this->m_gumballMachine = gumballMachine;}SoldOutState::~SoldOutState(){}void SoldOutState::insertQuarter(){    cout << "You can't insert a quarter, the machine is sold out" << endl;}void SoldOutState::ejectQuarter(){    cout << "You can't eject, you haven't inserted a quarter yet" << endl;}void SoldOutState::turnCrank(){    cout << "You turned, but there are no gumballs" << endl;}void SoldOutState::dispense(){    cout << "No gumball dispensed" << endl;}WinnerState::WinnerState(GumballMachine* gumballMachine){    this->m_gumballMachine = gumballMachine;}WinnerState::~WinnerState(){}void WinnerState::insertQuarter(){}void WinnerState::ejectQuarter(){}void WinnerState::turnCrank(){}void WinnerState::dispense(){}               

GumballMachine.h

#ifndef GUMBALLMACHINE_H#define GUMBALLMACHINE_H#include "State.h"namespace StatePattern {class GumballMachine {private:    State* m_soldOutState;    State* m_noQuarterState;    State* m_hasQuarterState;    State* m_soldState;    State* m_state;    int count;public:    GumballMachine(int numberGumballs = 0)    {        m_soldOutState = new SoldOutState(this);        m_noQuarterState = new NoQuarterState(this);        m_hasQuarterState = new HasQuarterState(this);        m_soldState = new SoldState(this);        this->count = numberGumballs;        m_state = m_soldOutState;        if (numberGumballs > 0) {            m_state = m_noQuarterState;        }    }       ~GumballMachine(){}    void insertQuarter()    // 放入硬币    {        m_state->insertQuarter();    }    void ejectQuarter()     // 退钱    {        m_state->ejectQuarter();    }    void turnCrank()        // 转动曲柄,拿到糖果    {        m_state->turnCrank();        m_state->dispense();    }    void setState(State* state)    {        this->m_state = state;    }    void releaseBall()    {        cout << "A gumball comes rolling out the slot..." << endl;        if (0 != count) {            count --;        }    }    void refill(int numberGumballs)     {        this->count = numberGumballs;        if (numberGumballs > 0) {            m_state = m_noQuarterState;        }    }    State* getSoldOutState()    {        return m_soldOutState;    }    State* getNoQuarterState()    {        return m_noQuarterState;    }    State* getHasQuarterState()    {        return m_hasQuarterState;    }    State* getSoldState()    {        return m_soldState;    }    int getCount()    {        return count;    }};}#endif

main.cpp

#include "GumballMachine.h"using namespace StatePattern;int main(){    GumballMachine* gumballMachine = new GumballMachine(1);    gumballMachine->insertQuarter();    gumballMachine->turnCrank();    gumballMachine->turnCrank();    delete gumballMachine;}

测试

测试结果如下图所示:
这里写图片描述

原创粉丝点击