本文的知识都出自于『Head First 设计模式』这本书中,
这里只是做一个概括,等后来忘记了拿来复习。
你可以也将本文作为复习参考,
不过要学的话,建议还是去看原书吧。
看这本书不一定非要会Java,我就是用C++实现的。
状态模式(State Pattern)允许对象在内部状态改变时改变他的行为,
由于状态模式完全改变对象行为,对象看起来就像修改了它的类。
如果不用状态模式,对象将使用变量或者枚举变量来存储当前状态,
然后执行行为时,就要用一堆if else来判断当前是什么状态。
这样一来,当状态需要增加修改删除时,就会非常麻烦,一堆if else能把你看晕。
经典的状态模式将状态封装成类,实现统一接口。
接口将规定状态将要执行什么行为,
当前状态的行为会导致对象的当前状态的改变。
对了,我曾经也见到过其他的状态模式,较经典状态模式有较大改变:
Finite State Machine in Unity
下面是经典状态模式的UML类图:
是不是很像策略模式?
不过,策略模式只是在你需要使用函数时提供具体函数,
那么你就要在Context类使用策略时,
主动选择使用那个策略。
而状态模式是自行通过行为改变状态,
并根据状态提供当前的行为。
状态模式对"开闭原则"的支持不太好,
对于可以切换状态的状态模式,
增加新的状态类需要修改那些负责状态转换的代码,
而且修改某个状态类的行为也需修改对应类的源代码。
猪这种动物一般吃了睡睡了吃,
所以猪只有两种状态。
猪吃完之后,就会想睡,睡醒之后,就会想吃,
这就构成了状态的切换。
State.h:
#pragma once
#include
//C++是先编译后链接,要是两个头文件互相include,会出现循环引用,所以在其中一个类里不包含另一个类的头文件,而是用Class先声明。
//在用到另一个类内容的.cpp文件中再include它的头文件。
class Pig;
class State
{
protected:
Pig* AimPig = nullptr;
public:
State(Pig* aimPig);
virtual void Handle() = 0;
};
class Eating :
public State
{
public:
Eating(Pig* aimPig) :State(aimPig) {}
virtual void Handle() override;
};
class Sleeping :
public State
{
public:
Sleeping(Pig* aimPig) :State(aimPig) {}
virtual void Handle() override;
};
Pig.h:
#pragma once
#include "State.h"
class Pig
{
private:
State* EatingState;
State* SleepingState;
State* CurrentState;
public:
Pig();
~Pig();
void Action();
void SetState(State* state);
State* GetEatingState();
State* GetSleepingState();
};
Pig.cpp:
#include "Pig.h"
Pig::Pig()
{
EatingState = new Eating(this);
SleepingState = new Sleeping(this);
CurrentState = EatingState;
}
Pig::~Pig()
{
delete EatingState;
delete SleepingState;
}
void Pig::Action()
{
CurrentState->Handle();
}
void Pig::SetState(State* state)
{
CurrentState = state;
}
State* Pig::GetEatingState()
{
return EatingState;
}
State* Pig::GetSleepingState()
{
return SleepingState;
}
State.cpp:
#include "State.h"
#include "Pig.h"
State::State(Pig* aimPig)
{
AimPig = aimPig;
}
void Eating::Handle()
{
std::cout << "I`m eating..." << std::endl;
AimPig->SetState(AimPig->GetSleepingState());
}
void Sleeping::Handle()
{
std::cout << "shushhhhhhhhhhhh..." << std::endl;
AimPig->SetState(AimPig->GetEatingState());
}
Main.cpp:
#include
#include "Pig.h"
#include "State.h"
int main()
{
Pig pig;
pig.Action();
pig.Action();
pig.Action();
pig.Action();
pig.Action();
pig.Action();
pig.Action();
pig.Action();
pig.Action();
}