状态模式(State)

Posted by LudoArt on April 24, 2019

状态模式——对象行为型模式

1、意图

允许一个对象再其内部状态改变时改变它的行为。对象看起来似乎修改了它的类。

2、适用性

  • 一个对象的行为取决于它的状态,并且它必须在运行时刻根据状态改变其行为。

  • 某个操作中含有庞大的多分支条件语句,而且该分支依赖于对象的状态。这个状态通常用一个或多个枚举常量来表示。通常,有多个操作包含这一相同的条件结构。状态模式将每一个条件分支放入一个独立的类中。

3、结构

图1 状态模式结构

图1 状态模式结构

4、参与者

  • 环境(Context)
    • 定义客户感兴趣的接口
    • 保存一个具体状态子类的实例,这个实例定义当前状态。
  • 状态(State)
    • 定义一个接口,用以封装与环境对象的一个特定状态相关的行为。
  • 具体状态子类(ConcreteState subclasses)
    • 每一个具体状态子类都实现了环境的一个状态相关的行为。

5、协作

  • Context对象将与状态相关的请求委托给当前的ConcreteState 对象处理。

  • Context可以将自身作为一个参数传递给处理该请求的状态对象,这使得在必要时状态对象可以访问Context对象。

  • Context是客户使用的主要接口。客户可用状态对象配置一个Context对象,一旦一个Context配置完毕,它的客户不再需要直接与状态对象打交道。

  • Context对象和ConcreteState 对象都可以决定哪个状态是另外哪一个状态的后继者,以及在何种条件下进行状态转换。

6、效果

  1. 它将与特定状态相关的行为局部化,并且将不同状态的行为分割开来

    A)状态模式需要对每一个Context可能取得的状态创建一个状态子类,所有与一个特定状态相关的行为都被包装到一个特定对象中,使得行为的定义局部化。这样,如果有新的状态以及它对应的行为需要定义时,可以很方便地通过定义新的子类的方式添加到系统中,不需要改动其它的类。

    B)由于每一个状态都被包装到类里面,就可以不必采用过程性处理方式,不必使用冗长的条件转移语句。

    C)状态模式的缺点是会增加子类的数目。

  2. 它使得状态转换显式化

    使用状态模式可以使得系统的状态转变变得很明显。由于不用一个变量的值来指明Context所处的状态,因此就不必担心修改这些属性值不当而造成的错误。

  3. State对象可被共享

    如果State对象没有实例变量——即它们表示的状态完全以它们的类型来编码——那么各Context对象可以共享一个State对象。当状态以这种方式被共享时,它们必然是没有内部状态,只有行为的轻量级对象。

7、实现

  1. 谁来定义状态的转换

    状态模式本身并没有规定哪一个参与者定义状态转换准则。

    1. 如果状态转换的条件固定,则让Context负责比较好。

    2. 如果让ConcreteState 自行决定下一个继任者是谁,以及在什么时候进行转换,则系统就更具灵活性。

    3. 在某些特殊条件下,需要由Context的客户负责。

  2. 基于表的另一种方法

    对每一个状态,一张表将每一个可能的输入映射到一个后继状态,将条件代码映射为一个查找表。

    优点:

    1. 可以通过更改数据而不是更改程序代码来改变状态转换的准则。

    缺点:

    1. 对表的查找通常不如(虚)函数调用效率高;
    2. 用统一的、表格的形式表示转换逻辑使得转换准则变得不够明确而难以理解。
    3. 通常难以加入伴随状态转换的一些动作。表驱动的方法描述了状态和它们之间的转换,但必须扩充这个机制以便在每一个转换上能够进行任意的计算。

    区别:

    1. State模式对与状态相关的行为进行建模;
    2. 表驱动的方法着重于定义状态转换。
  3. 创建和销毁State对象

    1. 事先创建所有的对象,然后不再消灭它们。适用于状态变化比较快和频繁、加载这些状态对象的成本比较高的情况。

    2. 动态创建当前所需要的状态对象,不要创立不需要的对象。如果事先不知道要使用哪一个状态对象,而一旦开始使用便不会频繁变更的情况下,这种选择为好。

  4. 使用动态继承

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());
}