设计模式---状态模式(C++实现)

        在状态模式(State Pattern)中,类的行为是基于它的状态改变的。这种类型的设计模式属于行为型模式。在状态模式中,通过创建不同的状态对象和一个随着状态变化的context对象。


意图

        允许对象在内部状态发生改变时,改变它的行为,对象看起来好像修改了它的类。


解决问题

        对象的行为依赖于它的状态(属性),并且可以根据它的状态改变而改变它的相关行为。


如何解决

        将各种具体的状态类抽象出来


优点

 1. 封装了转换规则

 2. 枚举可能的状态,在枚举状态之前需要确定确定状态种类

 3. 将所有与某个状态有关的行为放到一个类中,并且可以方便地增加新的状态,只需要改变对象状态即可改变对象的行为

 4.允许状态转换逻辑与状态对象合成一体,而不是某一个巨大的条件语句块

 5. 可以让多个环境对象共享一个状态对象,从而减少系统中对象的个数


缺点

1. 状态模式的使用必然会增加系统类和对象的个数

2. 状态模式的结构与实现都较为复杂,如果使用不当将导致程序结构和代码的混乱

3. 添加新的状态需要修改那些负责转换的源代码,否则无法转换到新增的状态,而且修改某个状态的行为也要修改源代码


使用场景

        1. 行为随状态改变而改变的场景

        2. 条件、分支语句的代替者


注意事项

        在行为受约束的时候使用状态模式,而且状态不超过5个


UML类图


C++实现

    例子:实现A 和 B状态转换


     这里利用状态模式来实现,具体状态就是状态A与状态B,然后上下文存在一个“转换状态”的方法。之后状态A与状态B共同接口就是抽象状态State。


code:

//状态模式

class Context; //类,上下文,的提前引用,主要是用于通过C++的编译,需要提前声明这个类

class State   //抽象状态
{
public:
	virtual void switch_state() = 0;
};
//每一个具体状态,都必须有私有变量上下文Context *context;
//每一个具体状态的构造方法,都必须用this->context=context;实现将自己注册到上下文中。
//不得在每一个具体状态中实现转换状态的方法switch_state(),只能在类外实现,因为C++禁止类的互相调用,
//否则会出现error C2027: 使用了未定义类型的错误
class StateA : public State //具体状态
{
public :
	StateA(Context  * _context)
		:context(_context)
	{}
	void  switch_state();

private:
	Context  *context;
};

class StateB :public State
{
public :
	StateB(Context * _context)
		:context(_context)
	{}
	void  switch_state();

private:
	Context * context;
};

class Context
{
	State   *stateA, *stateB, *state;
public :
	Context()
		:stateA(new StateA(this))
		, stateB(new StateB(this))
		, state(stateA)
	{}

	void switch_state()
	{
		state->switch_state();
	}

	void SetState(State* _state)
	{
		state = _state;
	}

	State* getStateA()
	{
		return stateA;
	}

	State* getStateB()
	{
		return stateB;
	}

};

//实现具体状态中,对应的转换方法
void StateA::switch_state()
{
	context->SetState(context->getStateB());
	cout << "已转换到状态B " << endl;
}
void StateB::switch_state()
{
	context->SetState(context->getStateA());
	cout << "已转换到状态A" << endl;
}


客户端:

int  test_State()  //状态模式
{
	Context* context = new Context();
	context->switch_state();
	context->switch_state();
	context->switch_state();
	context->switch_state();

	delete context;
	context = NULL;

	system("pause");
	return 0;
}


相关内容推荐