设计模式笔记-State模式

状态模式:事物在不同状态下会有不同表现(动作),经过不同动作后,又会转移到下一个不同的状态。这种问题可以用Switch/Case(if-else)搞定, 但如果case语句很多,就很麻烦,这种实现也没有将逻辑和动作分离,后期维护得不到保证!加case语句要修改原来代码,违反了“对扩展开放,对修改关闭”的原则!State 模式将每一个case分支都封装到独立的类中!

状态模式的具体实现类中有一个指向Context的引用。State 模式很好地实现了对象的状态逻辑和动作实现的分离, 状态逻辑分布在State 的派生类中实现,而动作实现则可以放在 Context 类中实现(这也是为什么 State 派生类需要拥有一个指向 Context 的指针)。这使得两者的变化相互独立, 改变 State 的状态逻辑可以很容易复用 Context 的动作, 也可以在不影响 State 派生类的前提下创建Context 的子类来更改或替换动作实现。


上下文环境(Context):定义客户需要的接口并维护一个ConcreteState实例,将与状态相关的操作委托给它来处理。

抽象状态(State):定义一个接口以封装使用上下文环境的的一个特定状态相关的行为。

具体状态(Concrete State):实现象状态定义的接口, 每一子类实现一个与Context的一个状态相关的行为。 

这个状态模式,网上的实现我觉得都不怎么好,主要是实现细节方面的!

这一篇,每次状态转换都new一个对象,delete一个对象,申请&释放内存好像挺耗时的!它描述的状态不是封闭的,我自己在实现的时候,就出现了问题--说出来可能丢人,就是new一个对象传入时,如果对象定义在后面C++是识别不到的,前向声明也没用,只能把.h和.cpp文件分开写,然后互相包含对方的.h文件!

另一篇,我觉得实现的很好,不过是PHP版本的,PHP是弱类型语言,有一些方便之处,比如所有状态类事先在Context类构造函数中new好。我在用C++改写时遇到了问题,什么头文件你包含我,我包含你的,太烦了,没成功!就简化成下面这样吧,不停申请&释放是挺耗时的。可以理解为一个开关,只有开和关两种状态!

class Context;

class LiftState {
public:
	LiftState();
	virtual ~LiftState();
	virtual void open(Context*) = 0;
	virtual void close(Context*) = 0;
};

class Context
{
public:

	Context();
	~Context();
	void setLiftState(LiftState* ls);
	LiftState* getLiftState();
	void open();
	void close();
private:
	LiftState* m_liftState;
};
LiftState::LiftState() {}

LiftState::~LiftState() {}

Context::Context() { m_liftState = NULL; }
Context::~Context() {}
void Context::setLiftState(LiftState* ls) {
	if (m_liftState) delete m_liftState;
	m_liftState = ls;
}
LiftState* Context::getLiftState() { return m_liftState; }
void Context::open() { m_liftState->open(this); }
void Context::close() { m_liftState->close(this); }
class OpenState : public LiftState {
public:
	OpenState();
	void open(Context* );
	void close(Context* );
};
OpenState::OpenState() {}
void OpenState::open(Context* ctx) {}

void OpenState::close(Context* ctx) {
	cout << "open->close!" << endl;
	ctx->setLiftState(new CloseState());
	ctx->getLiftState()->close(ctx);
}
#include"openstate.h"

class CloseState : public LiftState {
public:
	CloseState();
	void open(Context* );
	void close(Context* );
};
#include"openstate.h"
#include"closestate.h"

CloseState::CloseState() {}
void CloseState::open(Context* ctx) {
	cout << "close->open!" << endl;
	ctx->setLiftState(new OpenState());
	ctx->getLiftState()->open(ctx);
}

void CloseState::close(Context* ctx) {}
用户代码:

int main()
{
	Context* ct = new Context();
	ct->setLiftState(new OpenState());
	ct->open();
	ct->close();
	ct->open();
	return 0;
}

如果有想测试这个代码的,记得把各个代码块分文件存放!因为两个状态的CPP文件相互包含了对方的头文件,相互包含只能是声明,不能是定义!

代码里,state类里是通过传参的方式使用Context类的,而不能组合一个Context*类型的变量,因为Context类里已经组合了一个State*的变量了,相互包含的话,上面那条delete语句后,把调用setLiftState函数的指针对象自身都删除了,因为删除的State类对象指针中包含了Context对象指针!

阅读更多
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zhangjun03402/article/details/51549133
个人分类: 设计模式
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

不良信息举报

设计模式笔记-State模式

最多只允许输入30个字

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭