状态模式(State Pattern)属于行为型模式
在状态模式下,在情境中的一个对象可执行的行为会随着状态对象的改变而变化,因此状态模式又被归类为行为型模式。
适合使用此模式的情况:
1. 某对象的行为随着自身状态的改变而改变。
2. 以多重条件分支语句规范一个对象在不同状态下可执行的行为。
使用状态模式的优点:
1. 将与状态有关的一系列行为抽象出来作为一个State接口类,然后就可以根据不同的状态新增ConcreteState实现类,并封装不同的行为到类中。
简单来说,就是以状态区分不同的行为。
2. 状态转换逻辑可以封装在ConcreteState类中,从而减少大量条件语句。
3. 通过定义新的ConcreteState类就可以增加新的状态及转换逻辑。
使用状态模式的缺点:
1. 由于需要以状态区分行为,故整个系统中的类必定会增加。
2. 系统需求必须分析清楚,否则采用状态模式反而会造成系统结构混乱。
3. 状态模式并不完全符合"开闭原则"(Open-Closed Principle),对于把状态转换封装在状态类中的状态模式而言,系统中一旦加入了新的状态类,就需要修改原先的状态转换代码,否则将无法转换到新的状态。修改某个状态的行为也需要修改对应状态类的代码。
以下是呈现状态模式的类别图:
比较:
若是回忆一下会发现,怎么状态模式和策略模式那么像?
其实这两者可应用的场合十分类似,模式结构也都一样,只不过两者所关注的焦点不相同,
策略模式关注的是把算法(Algorithm)或行为(Behavior)封装在策略族中的一个实体类,Context的行为则委托给该实体类的实例执行。
状态模式关注的是状态族中的实体类之间可以轻松转换。
简单来说
策略模式关注的是行为的封装。
状态模式关注的则是状态间的转换。
以下是代码示例。
本篇文章实作的应用情境如下:
现有一手机。
手机有两种状态:开机、关机。
可对手机执行两种操作:开关机、打电话。
手机在不同状态下可表现的行为都不同。
示例代码如下:
状态类interface
[PhoneState.h]
// State interface
#pragma once
#include "stdio.h"
#include "MobilePhoneContext.h"
class MobilePhoneContext;
class PhoneState
{
public:
PhoneState(void){};
~PhoneState(void){};
virtual void changePowerState(MobilePhoneContext *context) = 0; // change the power mode
virtual void call() = 0; // make a phone call
};
状态实现类(开关机状态)
[OnState.h]
#pragma once
#include "PhoneState.h"
#include "OffState.h"
class OnState :
public PhoneState
{
public:
OnState(void){};
~OnState(void){};
void changePowerState(MobilePhoneContext *context); // change the power mode
void call(); // make a phone call
};
[OnState.cpp]
#include "OnState.h"
void OnState::changePowerState(MobilePhoneContext *context)
{
context->setState(new OffState());
}
void OnState::call()
{
printf("Call my girlfriend.\n");
}
[OffState.h]
#pragma once
#include "PhoneState.h"
#include "OnState.h"
class OffState :
public PhoneState
{
public:
OffState(void){};
~OffState(void){};
void changePowerState(MobilePhoneContext *context); // change the power mode
void call(); // make a phone call
};
[OffState.cpp]
#include "OffState.h"
void OffState::changePowerState(MobilePhoneContext *context)
{
context->setState(new OnState());
}
void OffState::call()
{
printf("The power is off!! It can't make a call.\n");
}
情境类(手机)
[MobilePhoneContext.h]
// Context
#pragma once
#include "PhoneState.h"
class PhoneState;
class MobilePhoneContext
{
public:
MobilePhoneContext(void);
MobilePhoneContext(PhoneState *state);
~MobilePhoneContext(void);
void setState(PhoneState *state);
void pressPower();
void call();
private:
PhoneState *state;
};
[MobilePhoneContext.cpp]
#include "MobilePhoneContext.h"
#include "OffState.h"
MobilePhoneContext::MobilePhoneContext(void)
{
this->state = new OffState();
}
MobilePhoneContext::MobilePhoneContext(PhoneState *state)
{
this->state = state;
}
MobilePhoneContext::~MobilePhoneContext(void)
{
delete this->state;
}
void MobilePhoneContext::setState(PhoneState *state)
{
this->state = state;
}
void MobilePhoneContext::pressPower()
{
state->changePowerState(this); // 状态的切换可以在ConcreteState类中指定,也可以在Context中根据条件指定state指向的ConcreteState类,本示例中采用的方法是前者。
}
void MobilePhoneContext::call()
{
state->call();
}
主程序
[StatePatternDemo.cpp]
#include "MobilePhoneContext.h"
#include "PhoneState.h"
#include "OffState.h"
void main()
{
MobilePhoneContext *phone = new MobilePhoneContext(new OffState());
phone->call();
phone->pressPower();
phone->call();
phone->pressPower();
phone->call();
getchar();
return;
}
Output
The power is off!! It can't make a call.
Call my girlfriend.
The power is off!! It can't make a call.
工程就不打包了,程序没有很复杂,应该很容易看明白,
之所以把关键部分类定义和实现分开,是希望能够将设计模式观念明确,也希望能够养成良好编程习惯。