状态模式——对象行为型模式
1、意图
允许一个对象再其内部状态改变时改变它的行为。对象看起来似乎修改了它的类。
2、适用性
-
一个对象的行为取决于它的状态,并且它必须在运行时刻根据状态改变其行为。
-
某个操作中含有庞大的多分支条件语句,而且该分支依赖于对象的状态。这个状态通常用一个或多个枚举常量来表示。通常,有多个操作包含这一相同的条件结构。状态模式将每一个条件分支放入一个独立的类中。
3、结构
4、参与者
- 环境(Context)
- 定义客户感兴趣的接口
- 保存一个具体状态子类的实例,这个实例定义当前状态。
- 状态(State)
- 定义一个接口,用以封装与环境对象的一个特定状态相关的行为。
- 具体状态子类(ConcreteState subclasses)
- 每一个具体状态子类都实现了环境的一个状态相关的行为。
5、协作
-
Context对象将与状态相关的请求委托给当前的ConcreteState 对象处理。
-
Context可以将自身作为一个参数传递给处理该请求的状态对象,这使得在必要时状态对象可以访问Context对象。
-
Context是客户使用的主要接口。客户可用状态对象配置一个Context对象,一旦一个Context配置完毕,它的客户不再需要直接与状态对象打交道。
-
Context对象和ConcreteState 对象都可以决定哪个状态是另外哪一个状态的后继者,以及在何种条件下进行状态转换。
6、效果
-
它将与特定状态相关的行为局部化,并且将不同状态的行为分割开来
A)状态模式需要对每一个Context可能取得的状态创建一个状态子类,所有与一个特定状态相关的行为都被包装到一个特定对象中,使得行为的定义局部化。这样,如果有新的状态以及它对应的行为需要定义时,可以很方便地通过定义新的子类的方式添加到系统中,不需要改动其它的类。
B)由于每一个状态都被包装到类里面,就可以不必采用过程性处理方式,不必使用冗长的条件转移语句。
C)状态模式的缺点是会增加子类的数目。
-
它使得状态转换显式化
使用状态模式可以使得系统的状态转变变得很明显。由于不用一个变量的值来指明Context所处的状态,因此就不必担心修改这些属性值不当而造成的错误。
-
State对象可被共享
如果State对象没有实例变量——即它们表示的状态完全以它们的类型来编码——那么各Context对象可以共享一个State对象。当状态以这种方式被共享时,它们必然是没有内部状态,只有行为的轻量级对象。
7、实现
-
谁来定义状态的转换
状态模式本身并没有规定哪一个参与者定义状态转换准则。
-
如果状态转换的条件固定,则让Context负责比较好。
-
如果让ConcreteState 自行决定下一个继任者是谁,以及在什么时候进行转换,则系统就更具灵活性。
-
在某些特殊条件下,需要由Context的客户负责。
-
-
基于表的另一种方法
对每一个状态,一张表将每一个可能的输入映射到一个后继状态,将条件代码映射为一个查找表。
优点:
- 可以通过更改数据而不是更改程序代码来改变状态转换的准则。
缺点:
- 对表的查找通常不如(虚)函数调用效率高;
- 用统一的、表格的形式表示转换逻辑使得转换准则变得不够明确而难以理解。
- 通常难以加入伴随状态转换的一些动作。表驱动的方法描述了状态和它们之间的转换,但必须扩充这个机制以便在每一个转换上能够进行任意的计算。
区别:
- State模式对与状态相关的行为进行建模;
- 表驱动的方法着重于定义状态转换。
-
创建和销毁State对象
-
事先创建所有的对象,然后不再消灭它们。适用于状态变化比较快和频繁、加载这些状态对象的成本比较高的情况。
-
动态创建当前所需要的状态对象,不要创立不需要的对象。如果事先不知道要使用哪一个状态对象,而一旦开始使用便不会频繁变更的情况下,这种选择为好。
-
-
使用动态继承
8、代码示例
class TCPOctetStream;
class TCPState;
//Context对象类
class TCPConnection {
public:
TCPConnection();
void ActiveOpen();
void PassiveOpen();
void Close();
void Send();
void Acknowledge();
void Synchronize();
void ProcessOctet(TCPOctetStream*);
private:
//将抽象State类设为友元类,以便于转换状态
friend class TCPState;
//增加该接口,让State对象显示地设定Context的当前状态
void ChangeState(TCPState*);
private:
//当前的状态
TCPState* _state;
};
// State抽象类
class TCPState
{
public:
virtual void Transmit(TCPConnection*, TCPOctetStream*);
virtual void ActiveOpen(TCPConnection*);
virtual void PassiveOpen(TCPConnection*);
virtual void Close(TCPConnection*);
virtual void Synchronize(TCPConnection*);
virtual void Acknowledge(TCPConnection*);
virtual void Send(TCPConnection*);
protected:
void ChangeState(TCPConnection*, TCPState*);
};
// ConcreteState子类
class TCPEstablished :public TCPState {
public:
static TCPState* Instance();
virtual void Transmit(TCPConnection*, TCPOctetStream*);
virtual void Close(TCPConnection*);
};
// ConcreteState子类
class TCPListen :public TCPState {
public:
static TCPState* Instance();
virtual void Send(TCPConnection*);
};
// ConcreteState子类
class TCPClosed :public TCPState {
public:
static TCPState* Instance();
virtual void ActiveOpen(TCPConnection*);
virtual void PassiveOpen(TCPConnection*);
};
//Context对象初始化为关闭状态
TCPConnection::TCPConnection() {
_state = TCPClosed::Instance();
}
//Context对象将与状态相关的请求委托给当前的ConcreteState对象处理
void TCPConnection::ChangeState(TCPState* s) {
_state = s;
}
void TCPConnection::ActiveOpen() {
_state->ActiveOpen(this);
}
void TCPConnection::PassiveOpen() {
_state->PassiveOpen(this);
}
void TCPConnection::Close() {
_state->Close(this);
}
void TCPConnection::Acknowledge() {
_state->Acknowledge(this);
}
void TCPConnection::Synchronize() {
_state->Synchronize(this);
}
//由具体子类实现具体行为
void TCPState::Transmit(TCPConnection*, TCPOctetStream*) {}
void TCPState::ActiveOpen(TCPConnection*) {}
void TCPState::PassiveOpen(TCPConnection*) {}
void TCPState::Close(TCPConnection*) {}
void TCPState::Synchronize(TCPConnection*) {}
//改变状态
void TCPState::ChangeState(TCPConnection* t, TCPState* s) {
t->ChangeState(s);
}
void TCPClosed::ActiveOpen(TCPConnection* t) {
//转换到TCPEstablished状态
ChangeState(t, TCPEstablished::Instance());
}
void TCPClosed::PassiveOpen(TCPConnection* t) {
//转换到TCPListen状态
ChangeState(t, TCPListen::Instance());
}
void TCPEstablished::Close(TCPConnection* t) {
//转换到TCPListen状态
ChangeState(t, TCPListen::Instance());
}
void TCPEstablished::Transmit(TCPConnection* t, TCPOctetStream* o) {
t->ProcessOctet(o);
}
void TCPListen::Send(TCPConnection* t) {
//转换到TCPEstablished状态
ChangeState(t, TCPEstablished::Instance());
}