状态模式:当一个对象内在状态改变时允许改变其行为,看起来像改变了棋类。
状态模式,顾名思义就是表示一个对象的状态,并且这些状态不一定是互斥的,常见的比如手机状态,有开机、关机、没有信号、正在通话。这四种状态中,比如手机处于关机状态时,就不能进行通话,只能进行开机;手机没有信号的时候,就不能进行打电话,只能进行关机;当手机出于开机状态的时候,手机可以没有信号也可以关机等。
所以手机不同的状态就会有不同状态下的行为,而且可以在不同的状态下进行切换。
那么根据以上状态可以搭建不同的手机使用场景。
首先定义手机的四种状态:
enum PHONESTATE{
STATE_POWERON,//开机
STATE_POWEROFF,//关机
STATE_NOSIGNAL,//没有信号
STATE_CALLING,//通话中
};
定义手机:
class MyPhone {
public:
void setPhoneState(PHONESTATE state);
PHONESTATE getPhoneState();
void powerOn();
void powerOff();
void calling();
void nosignal();
private:
PHONESTATE _phoneState;
};
void MyPhone::setPhoneState(PHONESTATE state) {
_phoneState = state;
}
PHONESTATE MyPhone::getPhoneState() {
return _phoneState;
}
void MyPhone::powerOn() {
switch(_phoneState) {
case STATE_POWERON:
printf("当前开机状态:不能再开机了!\n");
break;
case STATE_POWEROFF:
printf("当前关机状态:当然可以开机了!\n");
break;
case STATE_NOSIGNAL:
printf("当前手机没有信号:手机自然是开机状态,不能再次开机!\n");
break;
case STATE_CALLING:
printf("当前手机正在通话:现在已经是开机状态!\n");
break;
default:
break;
}
}
void MyPhone::powerOff() {
switch(_phoneState) {
case STATE_POWERON:
printf("当前开机状态:当然可以关机了!\n");
break;
case STATE_POWEROFF:
printf("当前关机状态:不能再关机了!\n");
break;
case STATE_NOSIGNAL:
printf("当前手机没有信号:当然可以关机了!\n");
break;
case STATE_CALLING:
printf("当前手机正在通话:不可以关机!\n");
break;
default:
break;
}
}
void MyPhone::calling() {
switch(_phoneState) {
case STATE_POWERON:
printf("当前开机状态:手机正在打电话!\n");
break;
case STATE_POWEROFF:
printf("当前关机状态:不能打电话!\n");
break;
case STATE_NOSIGNAL:
printf("当前手机没有信号:不可以打电话!\n");
break;
case STATE_CALLING:
printf("当前手机正在通话:现在已经是通话状态!\n");
break;
default:
break;
}
}
void MyPhone::nosignal() {
switch(_phoneState) {
case STATE_POWERON:
printf("当前开机状态:手机没有信号!\n");
break;
case STATE_POWEROFF:
printf("当前关机状态:不知道信号怎么样!\n");
break;
case STATE_NOSIGNAL:
printf("当前手机没有信号:...\n");
break;
case STATE_CALLING:
printf("当前手机正在通话:手机没有信号了,通话中断!\n");
break;
default:
break;
}
}
使用场景:
int main() {
MyPhone* myPhone = new MyPhone;
myPhone->setPhoneState(STATE_POWEROFF);
myPhone->powerOff();
myPhone->powerOn();
myPhone->calling();
myPhone->setPhoneState(STATE_NOSIGNAL);
myPhone->powerOn();
myPhone->powerOff();
myPhone->calling();
myPhone->nosignal();
return 0;
}
运行结果:
上面实现的手机在不同的状态下可以做的事情,使用大量的swich…case语句,如果要添加新的手机装填呢?比如手机信号弱等,是不是要重新每一个函数并且添加新的case语句,这就破坏了开闭原则。
有没有更好的办法呢?
答案是有的,咱们可以把手机不通状态提取出来,封装成公共的接口。
class IPhoneState {
public:
IPhoneState();
~IPhoneState();
//关机
virtual void powerOff() = 0;
//开机
virtual void powerOn() = 0;
//没有信号
virtual void onSignal() = 0;
//正在通话中
virtual void calling() = 0;
};
上面定义的函数是纯虚函数,子类必须继承实现的。
定义不通的状态子类。
开机状态:
//开机状态
class statePowerOn :public IPhoneState {
public:
void powerOff()override;
void powerOn()override;
void onSignal()override;
void calling()override;
};
void statePowerOn::powerOff() {
printf("当前开机状态:当然可以关机了!\n");
}
void statePowerOn::powerOn() {
printf("当前开机状态:不能再开机了!\n");
}
void statePowerOn::onSignal() {
printf("当前开机状态:手机没有信号!\n");
}
void statePowerOn::calling() {
printf("当前开机状态:手机正在打电话!\n");
}
关机状态:
//关机状态
class statePowerOff :public IPhoneState {
public:
void powerOff()override;
void powerOn()override;
void onSignal()override;
void calling()override;
};
void statePowerOff::powerOff() {
printf("当前关机状态:不能再关机了!\n");
}
void statePowerOff::powerOn() {
printf("当前关机状态:当然可以开机了!\n");
}
void statePowerOff::onSignal() {
printf("当前关机状态:不知道信号怎么样!\n");
}
void statePowerOff::calling() {
printf("当前关机状态:不能打电话!\n");
}
没有信号状态:
//没有信号状态
class stateNoSignal :public IPhoneState {
public:
void powerOff()override;
void powerOn()override;
void onSignal()override;
void calling()override;
};
void stateNoSignal::powerOff() {
printf("当前手机没有信号:当然可以关机了!\n");
}
void stateNoSignal::powerOn() {
printf("当前手机没有信号:手机自然是开机状态,不能再次开机!\n");
}
void stateNoSignal::onSignal() {
printf("当前手机没有信号:...\n");
}
void stateNoSignal::calling() {
printf("当前手机没有信号:不可以打电话!\n");
}
通话状态:
//通话状态
class stateCalling :public IPhoneState {
public:
void powerOff()override;
void powerOn()override;
void onSignal()override;
void calling()override;
};
void stateCalling::powerOff() {
printf("当前手机正在通话:不可以关机!\n");
}
void stateCalling::powerOn() {
printf("当前手机正在通话:现在已经是开机状态!\n");
}
void stateCalling::onSignal() {
printf("当前手机正在通话:手机没有信号了,通话中断!\n");
}
void stateCalling::calling() {
printf("当前手机正在通话:现在已经是通话状态!\n");
}
使用场景:
int main() {
Phone* phone = new Phone;
phone->setPhoneState(new statePowerOff());
phone->powerOff();
phone->powerOn();
phone->calling();
phone->setPhoneState(new stateNoSignal());
phone->powerOn();
phone->powerOff();
phone->calling();
phone->nosignal();
return 0;
}
运行结果:
运行结果和之前使用case语句是一样的,而且结构很清楚。
状态模式的优点:
1.避免使用过多的switch…case语句,提高系统的可维护性;
2.很好的体现开闭原则和单一职责原则,每个状态都是一个子类;