(1)定义:允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它的类。
①状态和行为,它们的关系可以描述为“状态决定行为”
②因状态是在运行期被改变,行为也会在运行期根据状态的改变而改变。看起来,同一个对象,在不同的运行时刻,行为是不一样的,就像是类被修改了一样。
(2)状态模式的结构和说明
①Context:环境,也称上下文,通常用来定义客户感兴趣的接口,同时维护一个来具体处理当前状态的实例对象。
②State:状态接口,用来封装与上下文的一个特定状态所对应的行为。
③ConcreteState:具体实现状态处理的类,每个类实现一个跟上下文相关的状态的具体处理。
思考状态模式
(1)状态模式的本质:根据状态来分离和选择行为
(2)状态和行为
①状态模式的功能就是把状态和状态对应的行为分离出来,每个状态所对应的功能处理封装在一个独立的类里。通过维护状态的变化,来调用不同状态对应的不同功能。
②为了操作不同的状态类,定义一个状态接口来约束它们,这样外部就可以面向这个统一的状态接口编程,而无须关心具体的状态类实现了。
③状态和行为是相关联的,它们的关系可以描述为状态决定行为。因状态是在运行期被改变,行为也会在运行期根据状态的改变而改变,看起来,同一个对象,在不同的运行时刻,行为是不一样的,就像是类被修改了一样。
(3)行为的平行性
①注意是平行性,而不是平等性。所谓的平行性指的是各个状态的行为所处的层次是一样的,相互独立的、没有关联的,是根据不同的状态来决定到底走平行线的哪一条。因为行为是不同的,当然对应的实现也是不同的,相互之间是不可替换的。
②平等性:强调用的可替换性,大家是同一行为的不同描述或实现,因此在同一个行为发生的时候,可以根据条件挑选任意一个实现来进行相应的处理。
③状态模式的结构和策略模式的结构完全一样。但是它们的目的、实现、本质却完全不同。还有行为之间的特性也是状态模式和策略模式的一个很重要的区别,状态模式的行为是平行性,不可相互替换的;而策略模式的行为是平等的,是可以相互替换的。
(4)Context和state
①在状态模式中,上下文持有state对象,但上下文本身并不处理跟状态相关的行为,而是把处理状态的功能委托给了状态对应的状态处理类来处理。
②在具体的状态处理类中经常需要获取上下文自身的数据,甚至在必要的时候回调上下文中的方法。因此,通常将上下文自身当作一个参数传递给具体的状态处理类。
③客户端一般只和上下文交互。客户端通常不负责运行期间状态的维护,也不负责决定后续到底使用哪一个具体的状态处理对象,这点与策略模式是不同的。
(5)不完美的OCP体验(开闭原则)
①修改功能:由于每个状态对应的处理己经封装到对应的状态类中了,要修改己有的某个状态的功能,直接进行修改那个类就可以了,对其他程序没有影响。
②添加新的实现类:得修改Context中request方法。这不完全遵循OCP原则。这要说明一下,设计原则是大家在设计和开发中尽量去遵守的,但不是一定要遵守,尤其是完全遵守。因为实际开发中,完全遵守那些原则几乎是不可能完成的任务。
(6)创建和销毁状态对象
①如果要进入的状态在运行时是不可知的,而且上下文是比较稳定的,不会经常改变状态,而且使用也不频繁的,可以在需要状态对象的时候创建,使用完销毁它们。
②如果状态改变很频繁,也就是需要频繁的创建状态对象,而且状态对象还存储着大量的数量信息,这种情况可以提前创建它们并且始终不销毁。
③如果无法确定状态改变是否频繁,而且有些状态对象的数据量大,有些比较小,一切都是未知的,可以采用延迟加载和缓存结合的方式,就是当第一次需要使用状态对象时创建,使用完后并不销毁对象,而是把这个对象缓存起来,等待一下次使用,而且在合适的时候,由缓存框架销毁状态对象。在实际工程开发过程中,这个方案是首选,因为它兼顾了前两种方案的优点,又避免了它们的缺点。
【编程实验】你公司力排万难终于获得某个酒店的系统开发项目,并且最终落到了你的头上。下图是他们系统的主要工作(够简单)。 当你第一眼看到这个系统的时候你就看出来了这是一个状态图,每个框框都代表了房间的状态,箭头表示房间状态的转换。分析如下:房间有三个状态:空闲、已预订、已入住,状态与状态之间可以根据客户的动作来进行转换。定义每个状态的值。
//声明文件
#include<iostream> #include<iomanip> using namespace std; class CAbsState{ public: virtual void BookRoom() = 0;//预订房间 virtual void UnsubscribeRoom() = 0;//退订房间 virtual void CheckInRoom() = 0;//入住 virtual void CheckOutRoom() = 0;//退房 }; //房间 class CRoom{ private: CAbsState* pFreeState;//空闲状态 CAbsState* pCheckInState;//入住状态 CAbsState* pBookedState;//预订状态 CAbsState* pCurrState;//当前状态 public: CRoom(); ~CRoom(); void BookRoom(); void UnsubscribeRoom(); void CheckInRoom(); void CheckOutRoom(); void RoomState(); public: void SetFreeState(CAbsState* freestate); CAbsState* GetFreeState(); void SetCheckInState(CAbsState* checkinstate); CAbsState* GetCheckInState(); void SetBookedState(CAbsState* bookedstate); CAbsState* GetBookedState(); void SetCurrState(CAbsState* currstate); CAbsState* GetCurrState(); }; //空闲状态只能预订和入住 class CFreeState : public CAbsState{ private: CRoom* pRoom; public: CFreeState(CRoom* room); void BookRoom(); void CheckInRoom(); void UnsubscribeRoom(); void CheckOutRoom(); }; //预定的房间可以退订和入住 class CBookedState : public CAbsState{ private: CRoom* pRoom; public: CBookedState(CRoom* room); void BookRoom(); void CheckInRoom(); void CheckOutRoom(); void UnsubscribeRoom(); }; // 入住可以退房 class CCheckInState : public CAbsState{ private: CRoom* pRoom; public: CCheckInState(CRoom* room); void BookRoom(); void CheckInRoom(); void CheckOutRoom(); void UnsubscribeRoom(); };
//实现文件
void CRoom::BookRoom(){ pCurrState->BookRoom();}//预订房间 void CRoom::UnsubscribeRoom(){pCurrState->UnsubscribeRoom();}//退订房间 void CRoom::CheckInRoom(){pCurrState->CheckInRoom();}//入住 void CRoom::CheckOutRoom(){pCurrState->CheckOutRoom();}//退房 void CRoom::RoomState(){cout << "该房间的状态是:" << typeid(*pCurrState).name() << endl;} void CRoom::SetFreeState(CAbsState* freestate){pFreeState = freestate;} CAbsState* CRoom::GetFreeState(){return pFreeState;} void CRoom::SetCheckInState(CAbsState* checkinstate){pCheckInState = checkinstate;} CAbsState* CRoom::GetCheckInState(){return pCheckInState;} void CRoom::SetBookedState(CAbsState* bookedstate){pBookedState = bookedstate;} CAbsState* CRoom::GetBookedState(){return pBookedState;} void CRoom::SetCurrState(CAbsState* currstate){pCurrState = currstate;} CAbsState* CRoom::GetCurrState(){return pCurrState;} CFreeState::CFreeState(CRoom* room){pRoom = room;} void CFreeState::BookRoom(){ cout << "您已经成功预订了..." << endl; pRoom->SetCurrState(pRoom->GetBookedState());//状态变成已经预订 } void CFreeState::CheckInRoom(){ cout << "您已经成功入住了..." << endl; pRoom->SetCurrState(pRoom->GetCheckInState());//状态变成已经入住 } void CFreeState::UnsubscribeRoom(){/*不需要做操作*/} void CFreeState::CheckOutRoom(){/*不需要做操作*/} //预定的房间可以退订和入住 CBookedState::CBookedState(CRoom* room){pRoom = room;} void CBookedState::BookRoom(){cout << "该房间已近给预定了..." << endl;} void CBookedState::CheckInRoom(){ cout << "入住成功" << endl; pRoom->SetCurrState(pRoom->GetCheckInState()); } void CBookedState::CheckOutRoom(){/*不需要做操作*/} void CBookedState::UnsubscribeRoom(){ cout << "退订成功,欢迎下次光临" << endl; pRoom->SetCurrState(pRoom->GetFreeState());//变成空闲状态 } // 入住可以退房 CCheckInState::CCheckInState(CRoom* room){pRoom = room;} void CCheckInState::BookRoom(){ cout << "该房间已经入住了..." << endl; } void CCheckInState::CheckInRoom(){ cout << "该房间已经入住了..." << endl; } void CCheckInState::CheckOutRoom(){ cout << "退房成功..." << endl; pRoom->SetCurrState(pRoom->GetFreeState());//状态变成空闲 } void CCheckInState::UnsubscribeRoom(){/*不需要做操作*/} CRoom::CRoom(){//房间的三个状态 pFreeState = new CFreeState(this); pCheckInState = new CCheckInState(this); pBookedState = new CBookedState(this); pCurrState = pFreeState;////初始状态为空闲 } CRoom::~CRoom(){ delete pFreeState; delete pCheckInState; delete pBookedState; }
//测试客户端
void main() { CRoom* pRoom1 = new CRoom(); CRoom* pRoom2 = new CRoom(); //第一间房 : 预订--->入住---预订 cout << "第一间房***************************" << endl; pRoom1->BookRoom(); pRoom1->CheckInRoom(); pRoom1->BookRoom();//Failed pRoom1->RoomState(); cout << "第二间房***************************" << endl; pRoom2->CheckInRoom(); pRoom2->BookRoom();//Failed pRoom2->CheckOutRoom(); pRoom2->BookRoom(); pRoom2->RoomState(); delete pRoom1; delete pRoom2; }