定义:当一个对象内在状态改变时,允许其改变行为,这个对象看起来像改变了其类。
翻译:就是没有某个状态,就不能做出某行为。因为类的动作一般是在任何情况下都可以调用的,受到状态的限制后,就像是基于不同的状态而换了不同的类一样,对着状态机理解就可。
类图摘自设计模式之禅:
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型开关,将所有开关结合形成对象行为表,通过控制表的内容,使对象的行为能符合任意状态,避免状态类过多带来的影响。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)