状态模式
1.1 分类
(对象)行为型
1.2 提出问题
开发一个糖果贩卖机,当投入硬币按下按钮,糖果机将掉落一枚糖果。当没有投入硬币,直接按下按钮,将会得到请投币的提示。
1.3 解决方案
允许一个对象在其内部状态改变时改变它的行为。对象看起来适合改变了它的类。
1.4 实现类图
- 上下文(Context)保存了对于一个具体状态对象的引用,并会将所有与该状态相关的工作委派给它。
- 状态(State)接口会声明特定于状态的方法。
- 具体状态(Concrete States)会自行实现特定于状态的方法。
- 上下文和具体状态都可以设置上下文的下个状态,并可通过替换连接到上下文的状态对象来完成实际的状态转换。
1.5 示例代码
#include <iostream>//class CandyMachine;
class State {
protected:// CandyMachine* m_candyMachine;
public://void setContext(CandyMachine* candyMachine) {// m_candyMachine = candyMachine;//}//virtual ~State(){}virtual void getCandy() = 0;virtual void returnCoin() = 0;virtual void putCoin() = 0;
};class NoCoinState :public State {virtual void getCandy() override {std::cout << "请先投币。\n";}virtual void returnCoin() override {std::cout << "你并没有投币。\n";}virtual void putCoin()override {std::cout << "投币成功。\n";}
};
class HaveCoinState :public State {virtual void getCandy() override {std::cout << "糖果投放中......\n";}virtual void returnCoin() override {std::cout << "硬币退回中......\n";}virtual void putCoin() override {std::cout << "重复投币。\n";}
};//Context
class CandyMachine {
private:State* m_currentState;State* m_haveCoinState;State* m_noCoinState;
public:CandyMachine() {m_haveCoinState = new HaveCoinState();m_noCoinState = new NoCoinState();m_currentState = m_noCoinState;std::cout << "糖果机:当前状态为--->" << typeid(*m_currentState).name() << "。\n";}~CandyMachine() {delete m_haveCoinState;delete m_noCoinState;}void putCoin() {std::cout << "糖果机:putCoin。\n";m_currentState->putCoin();transitionTo(m_haveCoinState);}void getCandy() {std::cout << "糖果机:getCandy。\n";m_currentState->getCandy();transitionTo(m_noCoinState);}void returnCoin() {std::cout << "糖果机:returnCoin。\n";m_currentState->returnCoin();transitionTo(m_noCoinState);}
private:void transitionTo(State* state) {m_currentState = state;std::cout << "糖果机:当前状态为--->" << typeid(*m_currentState).name() << "。\n";}
};
int main()
{CandyMachine* candyMachine = new CandyMachine;candyMachine->getCandy();candyMachine->returnCoin();candyMachine->putCoin();candyMachine->getCandy();candyMachine->returnCoin();delete candyMachine;
}
1.6 举个栗子
状态模式将根据当前回放状态,让媒体播放器中的相同控件完成不同的行为。
1.7 总结
1.7.1 优点
- 单一职责原则。将与特定状态相关的代码放在单独的类中。
- 开闭原则。无需修改已有状态类和上下文就能引入新状态。
- 通过消除臃肿的状态机条件语句简化上下文代码。
1.7.2 缺点
如果状态机只有很少的几个状态,或者很少发生改变,那么应用该模式可能会显得小题大作。