状态模式也是实际开发中应用非常广泛的一种设计模式,该模式可以有效地减小代码中switch和if的分支量,使代码更简洁,更容易扩展。
接下来我们举一个电梯控制系统的例子,电梯有4个功能,分别是关门、开门、运行、停止,同时也有4种状态,分别是关门状态、开门状态,运行状态、停止状态。
下面是使用状态模式前的实现方案
enum LiftStatus {
STATUS_OPEN = 0, // 开门状态
STATUS_CLOSE = 1, // 关门状态
STATUS_RUN = 2, // 运行状态
STATUS_STOP = 3 // 停止状态
};
class Lift {
public:
void open() { // 开门
switch (status)
{
case STATUS_OPEN:
break;
case STATUS_CLOSE:
status = STATUS_OPEN;
break;
case STATUS_RUN:
break;
case STATUS_STOP:
status = STATUS_OPEN;
break;
default:
break;
}
}
void close() { // 关门
switch (status)
{
case STATUS_OPEN:
status = STATUS_CLOSE;
break;
case STATUS_CLOSE:
break;
case STATUS_RUN:
break;
case STATUS_STOP:
break;
default:
break;
}
}
void run() { // 运行
switch (status)
{
case STATUS_OPEN:
break;
case STATUS_CLOSE:
status = STATUS_RUN;
break;
case STATUS_RUN:
break;
case STATUS_STOP:
status = STATUS_RUN;
break;
default:
break;
}
}
void stop() { // 停止
switch (status)
{
case STATUS_OPEN:
break;
case STATUS_CLOSE:
break;
case STATUS_RUN:
status = STATUS_STOP;
break;
case STATUS_STOP:
break;
default:
break;
}
}
private:
LiftStatus status;
};
从上述代码可以看出,主控制类Lift里面有一大串的switch语句,逻辑全都在Lift里面了,代码耦合度非常高,也不利于后续扩展状态。
接下来再看下使用状态模式来实现的代码
我们将每个状态都单独定义成类,状态的切换逻辑都有各个状态类去实现
// 电梯状态抽象类
class LiftStatus {
public:
LiftStatus(Lift* lift) : lift_(lift) {}
virtual void open() = 0; // 开门
virtual void close() = 0; // 关门
virtual void run() = 0; // 运行
virtual void stop() = 0; // 停止
protected:
Lift* lift_;
};
// 开门状态
class OpenStatus : public LiftStatus {
public:
OpenStatus(Lift* lift) : LiftStatus(lift) {}
void open() {}
void close() {
this->lift_->setStatus(1);
}
void run() {}
void stop() {}
};
// 关门状态
class CloseStatus : public LiftStatus {
public:
CloseStatus(Lift* lift) : LiftStatus(lift) {}
void open() {
this->lift_->setStatus(0);
}
void close() {}
void run() {
this->lift_->setStatus(2);
}
void stop() {}
};
// 运行状态
class RunStatus : public LiftStatus {
public:
RunStatus(Lift* lift) : LiftStatus(lift) {}
void open() {}
void close() {}
void run() {}
void stop() {
this->lift_->setStatus(3);
}
};
// 停止状态
class StopStatus : public LiftStatus {
public:
StopStatus(Lift* lift) : LiftStatus(lift) {}
void open() {
this->lift_->setStatus(0);
}
void close() {}
void run() {
this->lift_->setStatus(2);
}
void stop() {}
};
下面就是状态模式下的电梯主控制类Lift
class Lift {
public:
bool init() {
liftStatusGroup = {new OpenStatus(this), new CloseStatus(this), new RunStatus(this), new StopStatus(this)};
currentStatus = liftStatusGroup[0];
return true;
}
void open() { // 开门
currentStatus->open();
}
void close() { // 关门
currentStatus->close();
}
void run() { // 运行
currentStatus->run();
}
void stop() { // 停止
currentStatus->stop();
}
void setStatus(int index) { // 设置状态
currentStatus = liftStatusGroup[index];
}
private:
vector<LiftStatus*> liftStatusGroup;
LiftStatus* currentStatus;
};
很明显可以看出,Lift类中已经不存在switch分支,逻辑变得非常简单了, 后续需要扩展新状态的话,也不需要大规模修改Lift类里面的逻辑。
以下就是上述例子对应的类图