(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;
}
状态模式允许对象在内部状态改变时改变其行为,看起来就像修改了类一样。它将状态和行为封装在独立的类中,通过维护状态的变化来调用不同行为。状态模式中的行为具有平行性,不可互相替换,而策略模式的行为是平等的,可替换。在状态模式中,上下文不处理状态相关行为,而是委托给状态处理类。虽然状态模式可能在添加新实现类时违反OCP原则,但在实际开发中,它提供了灵活应对状态变化的方法。在处理状态对象时,可以按需创建和销毁,或者采用缓存策略。
4255

被折叠的 条评论
为什么被折叠?



