文章目录
- 一、什么是状态模式
- 二、状态模式的实现原理
- 三、状态模式的应用场景
- 四、状态模式的代码实现
一、什么是状态模式
状态模式是一种行为设计模式,它允许对象在内部状态改变时改变其行为。在状态模式中,对象的行为取决于其内部状态,并且可以在运行时根据不同的状态选择不同的行为。核心思想是将对象的状态封装成独立的类,并将不同状态对应的行为抽象成接口或基类。这样,当对象的状态发生改变时,可以动态地切换对象的行为,而无需修改对象本身的代码。
二、状态模式的实现原理
- 定义状态接口:创建一个状态接口,其中包含了所有具体状态类需要实现的方法。
- 实现具体状态类:创建多个具体状态类,每个类代表一个具体的状态,并实现状态接口中的方法。每个具体状态类负责处理特定状态下的行为。
- 维护状态切换:在上下文类中维护一个当前状态的引用,并提供方法来切换状态。上下文类根据当前状态来调用相应的具体状态类的方法。
- 客户端使用:客户端通过调用上下文类的方法来触发状态切换,从而改变对象的行为。
通过使用状态模式,可以将复杂的条件判断语句转化为一组独立的状态类,使得代码更加清晰、可维护和可扩展。
三、状态模式的应用场景
- 对象具有多个状态,且在不同状态下需要执行不同的操作。例如,一个订单对象可能有待支付、已支付、已发货等多个状态,每个状态下需要执行不同的操作。
- 对象的行为依赖于其内部状态,并且该状态可能在运行时发生改变。例如,一个电梯对象可能有停止、运行、故障等多个状态,且在运行时可以切换状态。
- 对象的行为包含大量的条件语句,导致代码复杂且难以维护。使用状态模式可以将每个状态的行为封装在独立的类中,使得代码更加清晰和可维护。
四、状态模式的代码实现
//+------------------------------------------------------------------+
//
// structure
//
// state
// |Context |o------------------>|State |
// |---------------| |--------|
// |Request() | |Handle()|
// | state.Handle()| |
// +--------------------+--- - - - -
// | |
// |ConcreteStateA| |ConcreteStateB|
// |--------------| |--------------|
// |Handle() | |Handle() |
//
class Context;
interface State
{void Handle(Context &context);
};
//
class ConcreteStateA:public State
{public:void Handle(Context& context);
};
//
class Context
{public:Context(State& state);~Context(void);State* State(void) {return m_state;}void State(State& state);void Request(void);protected:State* m_state;
};
//
Context::Context(State& state):m_state(&state)
{}
//
Context::~Context(void)
{if(CheckPointer(m_state)==1)delete m_state;
}
//
void Context::State(State& state)
{Print("context state changed to: ",&state);delete m_state;m_state=&state;
}
//
void Context::Request(void)
{Print("context is requesting its state ",m_state," which will handle this context");m_state.Handle(this);
}
//
class ConcreteStateB:public State
{public:void Handle(Context& context);
};
//
void ConcreteStateB::Handle(Context& context)
{Print("concrete state b (",&this,") is handling context and changing the context state");context.State(new ConcreteStateA);
}
//
void ConcreteStateA::Handle(Context& context)
{Print("concrete state a (",&this,") is handling context and changing the context state");context.State(new ConcreteStateB);
}
//
void OnStart(void)
{Context context(new ConcreteStateA);context.Request();context.Request();
}
// output
// context is requesting its state 2097152 which will handle this context
// concrete state a (2097152) is handling context and changing the context state
// context state changed to: 3145728
// context is requesting its state 3145728 which will handle this context
// concrete state b (3145728) is handling context and changing the context state
// context state changed to: 4194304