系列总链接:《大话设计模式》学习记录_net 大话设计-CSDN博客
参考:设计模式之状态模式 (C++ 实现)_设计模式的状态模式实现-CSDN博客
1.概述
状态模式允许一个对象在其内部状态改变时改变其行为。对象看起来像是改变了其类。使用状态模式可以将状态的相关行为放在各个状态类中,从而实现状态切换的灵活性和可扩展性。
用例子来说明,小明是个大学生(对象),简化其状态为:困,饿,饱;简化行为:吃饭,睡觉,打王者;默认情况下小明的行为和状态之间的关系会有偶然性,所以会存在逻辑上的if-else组合,要考虑地全面,这分支无疑会比较多,并且可以出错。如果从状态模式处理小明状态和行为的逻辑问题,可以把小明的状态抽象为状态类(State),各种具体的状态定为其的继承类(ConcreteState),小明具体如何在行为和状态间切换的场景类(Context)。这样会比较清晰,各自的状态类下和其相关的行为会比较清晰;如果想新增状态类,也比较方便。
2.结构与实现
结构:
状态模式主要由以下几个部分构成:
- Context (上下文):持有一个具体的状态对象,并在状态之间切换。
- State (状态接口):定义一个接口用于在具体状态中实现不同的行为。
- ConcreteState (具体状态):实现状态接口的具体类,每个状态都有自己的行为。
实现:
参照概述的中例子,实现如下:
State.h:
#ifndef STATE_H
#define STATE_H
#include <QDebug>
class People;
class State
{
public:
State() {}
virtual void sleep(People* xiaoming)=0;
virtual void eat(People* xiaoming)=0;
virtual void playWangzhe(People* xiaoming)=0;
};
//疲劳
class tiredState : public State
{
public:
tiredState(){}
void sleep(People* people);
void eat(People* people);
void playWangzhe(People* people);
};
//饥饿
class hungryState : public State
{
public:
hungryState(){}
void sleep(People* people);
void eat(People* people);
void playWangzhe(People* people);
};
//饱
class fullState : public State
{
public:
fullState(){}
void sleep(People* people);
void eat(People* people);
void playWangzhe(People* people);
};
#endif // STATE_H
State.cpp:
#include "State.h"
#include "People.h"
void tiredState::sleep(People *people)
{
qDebug() << "tired, go to sleeping and hungry.";
people->setState(new hungryState());
}
void tiredState::eat(People *people)
{
qDebug() << "tired, no want to eat...";
}
void tiredState::playWangzhe(People *people)
{
qDebug() << "tired, no want to play...";
}
void hungryState::sleep(People *people)
{
qDebug() << "hungry, no want to sleep...";
}
void hungryState::eat(People *people)
{
qDebug() << "hungry, go to eat and full.";
people->setState(new fullState());
}
void hungryState::playWangzhe(People *people)
{
qDebug() << "hungry, no want to play...";
}
void fullState::sleep(People *people)
{
qDebug() << "full, no want to sleep...";
}
void fullState::eat(People *people)
{
qDebug() << "full, no want to eat...";
}
void fullState::playWangzhe(People *people)
{
qDebug() << "full, go to play wangzhe and tired.";
people->setState(new tiredState());
}
People.h:
#ifndef PEOPLE_H
#define PEOPLE_H
#include "State.h"
class People
{
public:
People() {state = new tiredState();}
~People(){delete state;}
void setState(State* newState){
delete state;
state = newState;
}
void play();
void sleep();
void eat();
private:
State* state;
};
#endif // PEOPLE_H
People.cpp:
#include "People.h"
void People::play()
{
state->playWangzhe(this);
}
void People::sleep()
{
state->sleep(this);
}
void People::eat()
{
state->eat(this);
}
main.cpp:
#include <QCoreApplication>
#include "People.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
People* xiaoming = new People();
xiaoming->eat();
xiaoming->play();
xiaoming->sleep();
xiaoming->eat();
xiaoming->play();
xiaoming->eat();
delete xiaoming;
return 0;
}
运行效果:
tired, no want to eat...
tired, no want to play...
tired, go to sleeping and hungry.
hungry, go to eat and full.
full, go to play wangzhe and tired.
tired, no want to eat...
3.应用
状态机,游戏开发、网络协议处理、用户界面
4.优缺点及适用环境
优点:
- 简化对象的实现:通过将不同的状态逻辑分离到不同的类中,可以使原本复杂的条件语句变得更加简单明了。
- 符合开闭原则:当需要增加新的状态时,只需添加新的状态类而无需修改现有的代码,提高了系统的可扩展性。
- 提高内聚性:每个状态的行为被封装在一个单独的类中,增强了模块化和内聚性。
- 清晰的状态转换:状态模式使得状态之间的转换更加明确和易于管理。
缺点:
- 可能引入过多的类:对于每一个状态都需要创建一个新的类,这可能会导致系统中有过多的小类,增加了复杂度。
- 状态爆炸问题:如果状态之间存在多种组合,那么将会产生大量的状态类,维护起来较为困难。
- 上下文与状态之间的耦合:状态对象通常依赖于上下文对象,反之亦然,这可能导致较高的耦合度。
应用环境:
- 当一个对象在它的生命周期中需要根据不同的状态表现出不同的行为时。
- 当状态转换的逻辑复杂,使用多个条件语句来处理会使得代码难以理解和维护时。
- 当系统中存在大量相似但又有些许差异的状态或行为时,可以利用状态模式来减少重复代码并提高灵活性。
- 在有限状态机(FSM)中,状态模式是一个常见的选择,用于建模具有不同状态和事件驱动转换的系统。
综上所述,状态模式适用于那些有明显状态变化并且这些状态变化会导致行为变更的情况,尤其是在你希望保持代码整洁、易于扩展的情况下。