1、描述
状态是一种行为设计模式,让你能在一个对象的内部状态变化时改变其行为。
该模式将与状态相关的行为抽取到独立的状态类中,让原对象将工作委派给这些类的实例,而不是自行进行处理。
优点:1、结构清晰; 2、遵循设计原则; 3、封装性非常好;
缺点:子类会太多,也就是类膨胀。如果一个事物有很多状态也不稀奇,如果完全使用状态模式就会有太多的子类,不好管理。
2、结构图
- 上下文(Context)保存了对于一个具体状态对象的引用,并会将所有与该状态相关的工作委派给它。上下文通过状态接口与状态对象交互,且会提供一个设置器用于传递新的状态对象。
- 状态(State)接口会 声明特定于状态的方法。这些方法应能被其他所有具体状态所理解,因为你不希望某些状态所拥有的方法永远不会被调用。
- 具体状态(Concreate States)会自行实现特定于状态的方法。为了避免多个状态中包含相似代码,你可以提供一个封装有部分通用行为的中间抽象类。状态对象可存储对于上下文对象的反向引用。状态可以通过该引用从上下文获取所需信息,并且能触发状态转移。
3、C++代码
#include <iostream>
#include <typeinfo>
class Context;
//状态基类声明了一些所有的具体状态类都需要实现的方法;并且提供了一个与状态关联的Context对象
//的回溯引用。状态类使用该回溯引用转换Context到其他的状态。
class State {
protected:
Context *context_;
public:
virtual ~State() {
}
void set_context(Context *context) {
this->context_ = context;
}
virtual void Handle1() = 0;
virtual void Handle2() = 0;
};
//Context定义了客户感兴趣的接口。它还包括一个状态子类的实例,该实例代表了Context当前的状态。
class Context {
private:
State *state_;
public:
Context(State *state) : state_(nullptr) {
this->TransitionTo(state);
}
~Context() {
delete state_;
}
//Context允许在运行时修改状态
void TransitionTo(State *state) {
std::cout << "Context: Transition to " << typeid(*state).name() << ".\n";
if (this->state_ != nullptr)
delete this->state_;
this->state_ = state;
this->state_->set_context(this);
}
//Context将其部分行为委托给当前的状态对象
void Request1() {
this->state_->Handle1();
}
void Request2() {
this->state_->Handle2();
}
};
//具体的状态实现了与状态相关的不同的行为
class ConcreteStateA : public State {
public:
void Handle1() override;
void Handle2() override {
std::cout << "ConcreteStateA handles request2.\n";
}
};
class ConcreteStateB : public State {
public:
void Handle1() override {
std::cout << "ConcreteStateB handles request1.\n";
}
void Handle2() override {
std::cout << "ConcreteStateB handles request2.\n";
std::cout << "ConcreteStateB wants to change the state of the context.\n";
this->context_->TransitionTo(new ConcreteStateA);
}
};
void ConcreteStateA::Handle1() {
{
std::cout << "ConcreteStateA handles request1.\n";
std::cout << "ConcreteStateA wants to change the state of the context.\n";
this->context_->TransitionTo(new ConcreteStateB);
}
}
//客户端代码
void ClientCode() {
Context *context = new Context(new ConcreteStateA);
context->Request1();
context->Request2();
delete context;
}
int main() {
ClientCode();
return 0;
}