概述
前面文章介绍了代理模式(在这里),代理模式和状态模式都提供一个代理类,从结构上看,可以认为代理模式只是状态模式的一个特例,不同之处在于,代理模式控制对其实现类的访问,而状态模式动态地改变其实现类,当发现大多数或者所有函数都存在条件代码时,这种模式很有用。
状态模式
简单来说,状态模式通过一个前端对象来使用后端实现对象履行其职责,在前端对象生存期期间,状态模式从一个实现对象到另一个实现对象进行切换,以实现对于相同的函数调用产生不同的行为。
示例:
#include <iostream>
using namespace std;
class Creature
{
public:
Creature():isFrog(true) {}
void kiss(){isFrog = false;}
void greet(){
if(isFrog){
cout << "Ribbet!" << endl;
}
else{
cout << "Dearling!" << endl;
}
}
private:
bool isFrog;
};
int main()
{
Creature creature;
creature.greet();
creature.kiss();
creature.greet();
return 0;
}
从上述代码可以看到,greet()等任何其他所有函数在执行操作前都必须测试变量 isFrog,这样让代码变得非常笨拙,特别是在系统中加入额外的状态时情况会更加严重。
接下来我们通过状态模式来修改以上示例,将操作委派给状态对象:
#include <iostream>
using namespace std;
class Creature
{
private:
class State
{
public:
virtual string response() = 0;
virtual ~State();
};
class Frog : public State
{
public:
string response(){return "Ribbet!";}
virtual ~Frog();
};
class Prince : public State
{
public:
string response(){return "Daring!";}
virtual ~Prince();
};
State * state;
public:
Creature():state(new Frog()){}
void greet(){
cout << state->response() << endl;
}
void kiss(){
delete state;
state = new Prince();
}
};
int main()
{
Creature creature;
creature.greet();
creature.kiss();
creature.greet();
return 0;
}
(这里为了简单,使用了类嵌套定义,可以不必这样做)
适用场景
在下面两种情况下均可以使用状态模式:
1.一个对象的行为取决于它的状态,并且它必须在运行时刻根据状态改变它的行为;
2.一个操作中含有庞大的多分支的条件语句,且这些分支依赖于该对象的状态。这个状态通常用一个或多个枚举常量表示。通常,有多个操作包含这一相同的条件结构。State 模式将每一个条件分支放入一个独立的类中。这使得你可以根据自身情况将对象的状态作为一个对象,这一对象可以不依赖于其他对象而独立变化。