天天看点

[设计模式笔记]三. 行为型模式--22. State模式(状态)对象行为型模式(一)一. 意图二. 适用性三. 模式结构四. 角色说明五. 说明六. 我的理解七. 相关模式

行为型模式--State模式(状态)对象行为型模式

一. 意图

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

(状态与行为绑定, 状态变了, 行为也就随之改变.).

二. 适用性

在下面的两种情况下均可使用State模式:

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

一个操作中含有庞大的多分支的条件语句, 且这些分支依赖于该对象的状态. 这个状态通常用一个或多个枚举常量表示. 通常,  有多个操作包含这一相同的条件结构. State模式将每一个条件分支放入一个独立的类中. 这使得你可以根据对象自身的情况将对象的状态作为一个对象, 这一对象可以不依赖于其他对象而独立变化..

三. 模式结构

[设计模式笔记]三. 行为型模式--22. State模式(状态)对象行为型模式(一)一. 意图二. 适用性三. 模式结构四. 角色说明五. 说明六. 我的理解七. 相关模式

图1 

四. 角色说明

Context(上下文)

—定义客户感兴趣的接口。

—维护一个ConcreteState子类的实例, 这个实例定义当前状态.

State(状态)

—定义一个接口以封装与Context的一个特定状态相关的行为.

ConcreteState subclasses(具体状态子类)

—每一子类实现一个与Context的一个状态相关的行为.

协作

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

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

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

Context或ConceteState子类都可决定哪个状态是另外哪一个的后继者, 以及是在何种条件下进行状态转换.

五. 说明

1. State模式将所有与一个特定的状态相关的行为都放入一个对象中, 通过定义新的子类可以很容易的增加新的状态和转换.

2. State模式将不同状态的行为分布在多个State子类中. 这就增加了子类的数目, 相对于单个类的实现来说不够紧凑.

3. 它使得状态转换显式化, 为不同的状态引入独立的对象使得转换变得更加明确.

4. State对象可被共享.(使用Flyweight模式). 

六. 我的理解

1. 在写一个程序时, 程序的状态非常重要, 通常程序需要根据当前的状态来做对应的事情. 很常用的方法是, 使用一个值代表一个状态, 例如int nState = 0;等, 然后使用if或者switch来判断nState的值, 根据它的值做不同的事情.

2. 在State模式中, 状态则使用一个类对象表示, 一个状态就有一个类(运行时是类对象), 并且该类中有对应该类要做的事情的执行代码(状态与对应的行为被绑定在语言层次上, 而不是通过if/switch绑定在代码层次上).

3. 根据State模式的结构图. 

例如:

class Context
{
public:
	...
	void SetState(State* pState);
	void Request();
private:
	State* m_pState;
};
...
void Context::SetState(State* pState)
{
	m_pState = pState;
}

void Context::Request()
{
	if(m_pState)
	{
		m_pState->Handle();
	}
}

/
class State
{
public:
	...
	virtual void Handle();
};


class ConcreteStateA
{
public:
	...
	virtual void Handle();
};

void ConcreteStateA::Handle()
{
	int i = 0;
}

class ConcreteStateB
{
public:
	...
	virtual void Handle();
};

void ConcreteStateB::Handle()
{
	int k = 0;
}
......

// Client
// 调用(在某种情况下, Context的状态被改变了)
// 状态绑定
pContext->SetState(new ConcreteStateB);
...
// 执行Context当前状态的行为
pContext->Request();
           

4. 在实际应用中, a. 我们需要删除不使用的状态(状态改变时,,需要删除前一个状态对象), 但是如果状态变化很频繁而且状态对象比较大时, 频繁的删除会带来开销.(可以使用Flyweight模式, 如果条件满足的话.) b. Handle()函数可以有一些参数, 看需求.

5. State模式中把各个状态的操作分布到各个具体State子类中. 如果不使用State模式, 这些行为可能就集中到一个类中了.

6. 这种模式不只是用到状态的改变中, 例如曾经做过一个服务端, 它接收不同命令, 根据命令的不同来做不同的事情. 那实现的时候, 也可以使用这种模式, 一个命令对应一个类, 类中执行该命令对应的行为. 这场景与State模式是一致的.

七. 相关模式

Flyweight模式解释了何时以及怎样共享状态对象. 状态对象通常是Singleton.

继续阅读