[设计模式]行为模式-状态模式(C++描述)
second60 20180509
1. 什么是状态模式
对于一些人或事特,会有不同状态,而一个状态会在不同的表现下转移到下一个状态。
通常情况下,我们可能写个if..else语句进行判断,或switch语句进行判断,但是当状态越来越多时,代码将变得不可维护,可读性和扩展性变得很差。同时,状态逻辑和动作逻辑没有分离。而状态模式正是解决这样的问题。
状态模式,使我们把状态逻辑和动作实现分离出来,每个状态封装到一个类中。
2. 状态模式结构图
2.1 分析
1. 环境类:定义客户感兴趣的接口。维护一个ConcreteState子类的实例,这个实例定义当前状态。
2. 状态抽象类:定义状态的抽象接口,封装与Context相关的接口
3. 具体状态类:每一个子类实现一个状态相关的行为。
2.2 代码实现
class Context;
// 状态父类
class State
{
public:
virtual ~State(){}
virtual void OperationInterface(Context* context) = 0;
virtual void OperationChangeState(Context* context) = 0;
protected:
bool ChangeState(Context* context,State* state)
{
context->ChangeState(st);
}
};
// 具体状态类
class ConcreteStateA: public State
{
public:
void OperationInterface(Context* context)
{
//doing
}
void OperationChangeState(Context* context)
{
OperationInterface(context);
this->ChangeState(context, new ConcreteStateB());
}
};
// 具体状态类
class ConcreteStateB: public State
{
public:
void OperationInterface(Context* context)
{
//doing
}
void OperationChangeState(Context* context)
{
OperationInterface(context);
this->ChangeState(context, new ConcreteStateA());
}
};
//环境类
class Context
{
public:
Context(State* state){_state = state;}
~Context(){delete _state;}
bool ChangeState(State* state)
{
this->_state = state;
return true;
}
void OperationInterface()
{
_state->OperationInterface(this);
}
void OperationChangeState()
{
_state->OperationChangeState(this);
}
private:
friend class State;
State* _state;
};
int main()
{
State* st = new ConcreteStateA();
Context* con = new Context(st);
con->OperationChangeState();
con->OperationChangeState();
con->OperationChangeState();
//释放
return 0;
}
2.3 优点
1. 对象的状态逻辑和动作实现分离,状态分布在不同子类中
2. 封装了转换规则
3. 枚举了可能的状态,确定了状态的种类
4. 将所有与某个状态有关的行为放到了一个类中,方便增加新的状态
5. 多个环境对象可共享一个状态对象,减少对象的个数
2.4 缺点
1. 因为状态分布在不同子类中,所以整体状态图的理解成本大
2. 会增加系统类和对象的个数
3. 状态模式结构与实现都较为复杂,如果使用不当,导致结构和代码混乱
4. 新增状态,可能会修改相互转换的其他状态
2.5 状态模式和策略模式
状态模式和策略模式结构图很相似,但两者的用途不同。
状态模式主要适应对象状态改变时的不同处理策略
策略模式为具体算法和实现接口的解耦
3 适用场景
1、行为随状态改变而改变的场景。
2、条件、分支语句的代替者。
4 例子
1: 电梯的状态:开门,关门,停,运行
代码:
// 四种状态
enum ELiftState
{
ELiftState_Open = 1,
ELiftState_Close = 2,
ELiftState_Stop = 3,
ELiftState_Run = 4,
};
//电梯状态抽象类
class LiftState
{
public:
LiftState(){}
void setContext(Context* context){_context = context;}
virtual ~LiftState(){}
virtual void open() = 0;
virtual void close() = 0;
virtual void stop() = 0;
virutal void run() = 0;
private:
Context* _context;
};
// 具体状态类
class OpenningState:public LiftState
{
public:
OpenningState(Context* context):LiftState(context){}
void close()
{
this->_context->setLiftState(ELiftState_Close);
this->_context->getLiftState()->close();
}
void open()
{
cout << “continue openning” << endl;
}
void run(){}
void stop(){}
};
// 具体状态类
class ClosingState:public LiftState
{
public:
ClosingState(Context* context):LiftState(context){}
void close()
{
cout << “continue closing” << endl;
}
void open()
{
this->_context->setLiftState(ELiftState_Open);
this->_context->getLiftState()->open();
}
void run()
{
this->_context->setLiftState(ELiftState_Run);
this->_context->getLiftState()->run();
}
void stop()
{
this->_context->setLiftState(ELiftState_Stop);
this->_context->getLiftState()->stop();
}
};
// 具体状态类
class RunningState:public LiftState
{
public:
RunningState(Context* context):LiftState(context){}
void close(){}
void open(){}
void run()
{
cout << “keep running” << endl;
}
void stop()
{
this->_context->setLiftState(ELiftState_Stop);
this->_context->getLiftState()->stop();
}
};
class StoppingState:public LiftState
{
public:
StoppingState(Context* context):LiftState(context){}
void close(){}
void open()
{
this->_context->setLiftState(ELiftState_Open);
this->_context->getLiftState()->open();
}
void run()
{
this->_context->setLiftState(ELiftState_Run);
this->_context->getLiftState()->run();
}
void stop()
{
cout << “keep stop”<< endl;
}
};
class Context
{
public:
Context(){}
void setLiftState(LiftState* state)
{
_now_state = state;
state->setContext(this);
}
void open(){_now_state->open();}
void close(){_now_state->close();}
void run(){_now_state->run();}
void stop(){_now_state->stop();}
private:
LiftState * _now_state;
};
int main()
{
Context* context = new Context();
context->setLiftState(new ClosingState());
context->open();
context->close();
context->run();
context->stop();
}
5 总结
状态模式,把状态逻辑和动作分离,状态在状态子类中,动作在Context中.两者互相变化独立即,改变状态逻辑可以很容易复用Context的动作,也可以在不影响State派生类的前提下创建Context子类来更改或替换动作。
状态模式使用比较广泛,凡是涉及到状态转换,或分支判断的,都可以采用状态模式,但在有适用的情况下使用。
下节预告:观察都模式