State设计模式

 
每个人、事物在不同的状态下会有不同表现(动作),而一个状态又会在不同的表现下 转移到下一个不同的状态(State)。
 
有限状态自动机(FSM)是一个典型的状态不同,对输入有不同的响应(状态转移)。通常我们在实现这类系统会使用到很多的Switch/Case语句,Case某种状态,发生什么动作,Case另外一种状态,则发生另外一种状态。但是这种实现方式至少有以下两个问题:
1)当状态数目不是很多时,Switch/Case可能可以搞定。但是当状态数目很多的时候(实际系统中也正是如此),维护一大组的Switch/Case语句将是一件异常困难并且容易出错的事情。
2)状态逻辑和动作实现没有分离。在很多的系统实现中,动作的实现代码直接写在状态的逻辑当中。这带来的后果就是系统的扩展性和维护得不到保证。
 
State模式就是被用来解决上面列出的两个问题的,在State模式中我们将状态逻辑和动作实现进行分离。当一个操作中要维护大量的case分支语句,并且这些分支依赖于对象的状态。State模式将每一个分支都封装到独立的类中。
 
//state.h
#ifndef _STATE_H_
#define _STATE_H_
class Context; //前置声明
class State
{
public:
State();
virtual ~State();
virtual void OperationInterface(Context* ) = 0;
virtual void OperationChangeState(Context*) = 0;
protected:
bool ChangeState(Context* con,State* st);
private:
//bool ChangeState(Context* con,State* st);
};
class ConcreteStateA : public State
{
public:
ConcreteStateA();
virtual ~ConcreteStateA();
virtual void OperationInterface(Context* );
virtual void OperationChangeState(Context*);
protected:
 
private:
};
class ConcreteStateB : public State
{
public:
ConcreteStateB();
virtual ~ConcreteStateB();
virtual void OperationInterface(Context* );
virtual void OperationChangeState(Context*);
protected:
 
private:
};
#endif //~_STATE_H_
 
 
//State.cpp
#include "State.h"
#include "Context.h"
#include <iostream>
using namespace std;
State::State()
{
}
State::~State()
{
}
void State::OperationInterface(Context* con)
{
cout<<"State::.."<<endl;
}
bool State::ChangeState(Context* con,State* st)
{
con->ChangeState(st);
return true;
}
void State::OperationChangeState(Context* con)
{
}
ConcreteStateA::ConcreteStateA()
{
}
ConcreteStateA::~ConcreteStateA()
{
}
void ConcreteStateA::OperationInterface(Context* con)
{
cout<<"ConcreteStateA::OperationInterface......"<<endl;
}
 
void ConcreteStateA::OperationChangeState(Context* con)
{
OperationInterface(con);
this->ChangeState(con,new ConcreteStateB());
}
ConcreteStateB::ConcreteStateB()
{
}
ConcreteStateB::~ConcreteStateB()
{
}
void ConcreteStateB::OperationInterface(Context* con)
{
cout<<"ConcreteStateB::OperationInterface......"<<endl;
}
void ConcreteStateB::OperationChangeState(Context* con)
{
OperationInterface(con);
this->ChangeState(con,new ConcreteStateA());
}
 
 
//context.h
#ifndef _CONTEXT_H_
#define _CONTEXT_H_
class State;
class Context
{
public:
Context();
Context(State* state);
~Context();
void OprationInterface();
void OperationChangState();
protected:
 
private:
friend class State; //表明在State类中可以访问Context类的private字段
bool ChangeState(State* state);
private:
State* _state;
};
#endif //~_CONTEXT_H_
 
 
//context.cpp
#include "Context.h"
#include "State.h"
Context::Context()
{
}
Context::Context(State* state)
{
this->_state = state;
}
Context::~Context()
{
delete _state;
}
void Context::OprationInterface()
{
_state->OperationInterface(this);
}
bool Context::ChangeState(State* state)
{
this->_state = state;
return true;
}
void Context::OperationChangState()
{
_state->OperationChangeState(this);
}
 
 
//main.cpp
#include "Context.h"
#include "State.h"
#include <iostream>
using namespace std;
int main(int argc,char* argv[])
{
State* st = new ConcreteStateA();
Context* con = new Context(st);
con->OprationInterface();
con-> OprationInterface ();
con->OprationInterface();
if (con != NULL)
delete con;
if (st != NULL)
st = NULL;
return 0;
}
 
 
State模式在实现中,有两个关键点:
1)将State声明为Context的友元类(friend class),其作用是让State模式访问Context的protected接口ChangeSate()。
2)State及其子类中的操作都将Context*传入作为参数,其主要目的是State类可以通过这个指针调用Context中的方法(在本示例代码中没有体现)。这也是State模式和Strategy模式的最大区别所在。
 
运行了示例代码后可以获得以下的结果:连续3次调用了Context的OprationInterface()因为每次调用后状态都会改变(A-B-A),因此该动作随着Context的状态的转变而获得了不同的结果。
 
State模式的应用也非常广泛,从最高层逻辑用户接口GUI到最底层的通讯协议都有其用武之地。
 
State模式和Strategy模式又很大程度上的相似:它们都有一个Context类,都是通过委托(组合)给一个具有多个派生类的多态基类实现Context的算法逻辑。两者最大的差别就是State模式中派生类持有指向Context对象的引用,并通过这个引用调用Context中的方法,但在Strategy模式中就没有这种情况。因此可以说一个State实例同样是Strategy模式的一个实例,反之却不成立。实际上State模式和Strategy模式的区别还在于它们所关注的点不尽相同:State模式主要是要适应对象对于状态改变时的不同处理策略的实现,而Strategy则主要是具体算法和实现接口的解耦(coupling),Strategy模式中并没有状态的概念(虽然很多时候有可以被看作是状态的概念),并且更加不关心状态的改变了。
 
State模式很好地实现了对象的状态逻辑和动作实现的分离,状态逻辑分布在State的派生类中实现,而动作实现则可以放在Context类中实现(这也是为什么State派生类需要拥有一个指向Context的指针)。这使得两者的变化相互独立,改变State的状态逻辑可以很容易复用Context的动作,也可以在不影响State派生类的前提下创建Context的子类来更改或替换动作实现。
 
State模式问题主要是逻辑分散化,状态逻辑分布到了很多的State的子类中,很难看到整个的状态逻辑图,这也带来了代码的维护问题。
 
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值