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



