设计模式,状态模式:电梯先关门后移动,c++实现

设计模式,状态模式:电梯先关门后移动,c++实现,第1张

设计模式,状态模式:电梯先关门后移动,c++实现 状态模式:电梯想要移动首先得是关门的。

定义:当一个对象内在状态改变时,允许其改变行为,这个对象看起来像改变了其类。

翻译:就是没有某个状态,就不能做出某行为。因为类的动作一般是在任何情况下都可以调用的,受到状态的限制后,就像是基于不同的状态而换了不同的类一样,对着状态机理解就可。

类图摘自设计模式之禅:

state抽象状态角色,接口或抽象类:
负责对象状态定义,封装环境角色以实现状态切换。
封装对象的所有功能函数,已满足实现不同的状态。

concretestate具体状态角色,两个职责:
本状态的行为管理,就是本状态下要干的事。
趋向状态处理,就是本状态过渡到其他状态的条件。

context环境角色:
定义客户端需要的接口,负责具体状态的切换。
其实就是物体对象本身或指针啦,物体通过转换状态适应需求,而适应需求就是物品指针委托状态类完成的。

环境角色的不成文约束:
将状态对象声明为静态常量,有几个状态声明几个静态常量。
环境角色具有状态抽象角色定义的所有行为,具体执行使用委托方式。

优点:
1.结构清晰,避免了过多的switch case或者if else,避免了程序复杂性,提高了系统可维护性。
2.很好的体现了开闭原则和单一职责原则,每个状态都是一个子类,增加状态就增加子类,修改状态就修改子类。
3.封装性好,状态变换放在类的内部,状态变换放在类的外部。

缺点:
子类太多容易类膨胀,一个事物状态太多就会有很多子类,不好管理,不过也好解决,比如在数据库中建立一个状态表。

使用场景:
行为随状态而改变的场景:状态机
条件语句的代替者。

注意事项:
行为在收到状态约束的情况下可以使用状态模式,但对象的状态最好不要超过5个。

状态需要自由切换时,需要考虑和建造者模式或其他模式混合使用,一般来说状态会有很多种,与其相对的是动作的组合模式也会很多,但动作不会增加。

代码示例:状态模式中也需要两个类相互包含,因此c++实现是需要注意写法,还是如之前博文中说的,分三步
1.声明所有类
2.声明类中函数和数据
3.类外实现函数

class Lift;
class StateOfLift;
class LiftOpen;
class LiftClose;
class LiftMove;
class LiftStop;

class Lift
{
public:
	static StateOfLift* IsOpened;
	static StateOfLift* IsClosed;
	static StateOfLift* IsMoving;
	static StateOfLift* IsStopped;

	void Open();

	void Close();

	void Move();

	void Stop();

	void SetState(StateOfLift* stateOfLift);

protected:
	StateOfLift* mStateOfLift;
};

class StateOfLift
{
public:
	virtual void Open() = 0;
	virtual void Close() = 0;
	virtual void Move() = 0;
	virtual void Stop() = 0;

	void SetLift(Lift* lift)
	{
		mLift = lift;
	}

protected:
	Lift* mLift;
};

//电梯门是开着的
class LiftOpen :public StateOfLift
{
	virtual void Open()
	{
		cout << "门开的时间延长" << endl;
	}
	virtual void Close()
	{
		cout << "关门" << endl;
		mLift->SetState(Lift::IsClosed);
	}
	virtual void Move()
	{
		cout << "门未关闭,无法移动" << endl;
	}
	virtual void Stop()
	{
		cout << "电梯不动" << endl;
	}
};

//电梯门是关着的
class LiftClose :public StateOfLift
{
	virtual void Open()
	{
		cout << "开门" << endl;
		mLift->SetState(Lift::IsOpened);
	}
	virtual void Close()
	{
		cout << "门是关着的" << endl;
	}
	virtual void Move()
	{
		cout << "门已关闭,电梯移动" << endl;
		mLift->SetState(Lift::IsMoving);
	}
	virtual void Stop()
	{
		cout << "门已关闭,电梯停止移动" << endl;
		mLift->SetState(Lift::IsStopped);
	}
};

//电梯是移动着的
class LiftMove :public StateOfLift
{
	virtual void Open()
	{
		cout << "电梯移动中,门无法开启" << endl;
	}
	virtual void Close()
	{
		cout << "门是关着的" << endl;
	}
	virtual void Move()
	{
		cout << "电梯是移动着的" << endl;
	}
	virtual void Stop()
	{
		cout << "电梯移动停止" << endl;
		mLift->SetState(Lift::IsStopped);
	}
};

//电梯是停止的
class LiftStop :public StateOfLift
{
	virtual void Open()
	{
		cout << "开门" << endl;
		mLift->SetState(Lift::IsOpened);
		
	}
	virtual void Close()
	{
		cout << "关门" << endl;
		mLift->SetState(Lift::IsClosed);
	}
	virtual void Move()
	{
		cout << "电梯移动" << endl;
		mLift->SetState(Lift::IsStopped);
	}
	virtual void Stop()
	{
		cout << "电梯不动" << endl;
	}
};

StateOfLift* Lift::IsClosed = new LiftClose();
StateOfLift* Lift::IsMoving = new LiftMove();
StateOfLift* Lift::IsOpened = new LiftOpen();
StateOfLift* Lift::IsStopped = new LiftStop();

void Lift::Open()
{
	mStateOfLift->Open();
}

void Lift::Close()
{
	mStateOfLift->Close();
}

void Lift::Move()
{
	mStateOfLift->Move();
}

void Lift::Stop()
{
	mStateOfLift->Stop();
}

void Lift::SetState(StateOfLift* stateOfLift)
{
	mStateOfLift = stateOfLift;
	stateOfLift->SetLift(this);
}



void func()
{
	Lift* lift = new Lift();
	lift->SetState(Lift::IsClosed);

	lift->Move();
	lift->Open();
	lift->Stop();
	lift->Open();
	lift->Move();
	lift->Close();
}

int main()
{
	func();
	return 0;
}


在这个运行结果中,我们可以看到电梯的动作受到了其当前状态的影响,实现了状态模式的效果。
深入:状态模式理论上每个状态都对应一个静态类对象,对象的状态是不好确定的,这导致类数量过大,为了避免状态过多或需求本身过多,我们可以绕过状态直接控制对象的行为,比如给每个行为增加一个bool型开关,将所有开关结合形成对象行为表,通过控制表的内容,使对象的行为能符合任意状态,避免状态类过多带来的影响。

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/zaji/3970357.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-10-21
下一篇 2022-10-21

发表评论

登录后才能评论

评论列表(0条)

保存