9、C++设计模式及实际应用-状态模式

状态模式也是实际开发中应用非常广泛的一种设计模式,该模式可以有效地减小代码中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类里面的逻辑。

以下就是上述例子对应的类图
在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值