小程序设计模式之状态模式实践-蓝牙配网

引言

相信大家在开发的过程中或多或少遇到过某些事件存在多种状态,不知道大家都是怎么处理的,是不是需要花大量时间去维护这些状态。随着物联网的普及,家电等产品的配网功能也越发普及。本文就以微信小程序蓝牙配网如何使用状态模式,因为配网涉及到多个状态。

蓝牙配网

整个过程一般就是用户通过小程序搜索到设备,然后通过蓝牙连接上设备,再把家中的路由器信息发送给设备,最后设备通过收到的信息连上路由器,接入网络。

状态机

我们先先来看看一般的做法
① 首先,我们找出蓝牙配网中的一些状态:
1. 蓝牙未连接
2. 蓝牙连接中
3. 蓝牙已连接
4. 路由信息已接收
5. WIFI连网中
6. 配网成功
② 然后,定义一些常量来指定各个状态:
const UNCONNECTED = 1;
const CONNECTING = 2;
const CONNECTED = 3;
const RECEIVED = 4;
const WIFI_CONNECTING = 5;
const WIFI_CONNECTED = 6;

let state = UNCONNECTED;

③ 最后我们创建一个状态机的类,比如在连接的函数里处理每个状态下的情况:

在这里插入图片描述
④ 使用状态机的类
在这里插入图片描述
这看起来没什么问题,也挺好用。但某次会议上,某人提出了现在的方式有缺陷,不是很安全,应该在蓝牙连接后进行设备的认证。最后领导拍板,在原来的基础上增加几个状态。
既然要更改,那就赶紧召集开发人员,结果开发人员一看,沃日要修改好多地方:
1.首先可能要增加两种新的状态:
const AUTHENTCATING = 7;
const AUTHENTCATED = 8;
2.然后在那些处理状态的方法里增加类似else if的东西,太多了,太多了。
就在程序员炸裂的边缘,你们的架构师瞄了眼说,怎么没有用状态模式,程序员一脸无奈的看着架构师。
好了题外话说到这,进入本次的正题——状态模式

什么是模式

模式是指在某种情境下,针对某问题的某种解决方案。

何时用设计模式

在设计的时候,如果遇到某个问题,而且该问题不能用简单的设计就能解决,那么可以试着利用某个模式帮助我们解决那个问题。

新的设计

我们把每个状态都看成一个对象,然后在动作发生时委托给当前状态。
首先,我们定义个抽象类State,在这个类内,蓝牙配网的每个动作都有一个对应的函数。
然后为每个状态实现状态类。这些类将负责对应状态下的行为。
最后,将动作委托到状态类。

重新定义State类

class AbstractState {
	constructor(stateController) {
    	this.stateController = stateController; // 状态控制类
  	}
	
	/**
   * 连接蓝牙设备
   * @see UnConnectState
   */
  connect() {}

  /**
   * 断开蓝牙设备
   * @see UnConnectState
   */
  disconnect() {}

  /**
   * 蓝牙连接成功
   * @see UnConnectState
   */
  connectSuccess() {}

  /**
   * 蓝牙连接失败
   * @see UnConnectState
   */
  connectFail() {}

  /**
   * 路由数据接收完成
   * @see ReceivedState
   */
  received() {}

  /**
   * 认证中
   * @see AuthenticatingState
   */
  authenticating() {}

  /**
   * 认证完成
   * @see AuthenticatedState
   */
  authenticated() {}

  /**
   * 充电完成
   * @see WifiConnectingState
   */
  wifiConnecting() {}

  /**
   * 时间同步完成
   * @see WifiConnectedState
   */
  wifiConnected() {}

  /**
   * 获取状态ID
   */
  getStateId() {
    return 0;
  }

  /**
   * 释放资源
   * @see ConnectedState
   */
  onRelease() {}
}

module.exports = AbstractState

实现各状态类

UnConnectState类

import AbstractState from './AbstractState'

class UnConnectState extends AbstractState { // 未连接状态只处理连接的事件
  constructor(stateController) {
    super(stateController);
  }

  /**
   * @override
   * @description 连接设备
   */
  connect() { // 这里只是实例,具体需要怎么处理还要更具体的业务逻辑
    const ble = this.stateController.getBLE();
    if (ble) {
      this.stateController.setState(this.stateController.getConnectingState());
      this.stateController.notifyAll();
      ble.initBleAdapter();
    }
  }

  getStateId() {
    return 100;
  }
}
module.exports = UnConnectState

ConnectingState类

import AbstractState from './AbstractState'

class ConnectingState extends AbstractState { // 蓝牙连接状态的类
  constructor(stateController) {
    super(stateController);
  }

  connectSuccess() {
    this.stateController.setState(this.stateController.getConnectedState());
    this.stateController.notifyAll();
  }

  connectFail() {
    this.stateController.setState(this.stateController.getUnConnectState());
    this.stateController.notifyAll();
  }

  disconnect() {
    this.stateController.setState(this.stateController.getUnConnectState());
    this.stateController.notifyAll();
  }

  getStateId() {
    return 101;
  }
}
module.exports = ConnectingState

ConnectedState类

import AbstractState from './AbstractState'

class ConnectedState extends AbstractState {
  constructor(stateController) {
    super(stateController);
  }

  connectFail() {
    this.stateController.setState(this.stateController.getUnConnectState());
    this.stateController.notifyAll();
    // 结束发送路由的命令
  }

  authenticating() {    this.stateController.setState(this.stateController.getAuthenticatingState());
    // 发送认证的指令
  }

  disconnect() {
    this.stateController.setState(this.stateController.getUnConnectState());
    this.stateController.notifyAll();
  }

  getStateId() {
    return 102;
  }

  onRelease() {
    
  }
}
module.exports = ConnectedState

由于篇幅,其他的状态类就不在这里写了。

StateController类

import UnConnectState from './UnConnectState';
import ConnectingState from './ConnectingState';
import ConnectedState from './ConnectedState';

const DEBUG = true;
const TAG = 'StateController#';

let mUnConnectState = null;
let mConnectingState = null;
let mConnectedState = null;
let mState = null;

let mBle = null;

let STATE_CONTROLLER = null;
/** 页面监听器列表 */
let mPageObservers = new Set();


class StateController {
  constructor() {
    mUnConnectState = new UnConnectState(this);
    mConnectingState = new ConnectingState(this);
    mConnectedState = new ConnectedState(this);
    mState = mUnConnectState;
  }

  static getInstance() {
    if (STATE_CONTROLLER == null) {
      STATE_CONTROLLER = new StateController();
    }
    return STATE_CONTROLLER;
  }

  addPage(page) {
    mPageObservers.add(page);
  }

  deletePage(page) {
    mPageObservers.delete(page);
  }

  clearPages() {
    mPageObservers.clear();
  }

  /**
   * 连接设备,在调用之前确保已经调用过#setDeviceId(deviceId)
   */
  connect() {  
    mState.connect();
  }

  /**
   * 断开设备连接
   */
  disconnect() {
    mState.disconnect();
  }

  /**
   * 设备连接成功
   */
  connectSuccess() {
    mState.connectSuccess();
  }

  /**
   * 设备连接失败
   */
  connectFail() {
    mState.connectFail();
  }

  /**
   * 设置状态
   * @param {*} state 需要设置的状态
   * @see UnConnectState
   * @see ConnectingState
   * @see ConnectedState
   */
  setState(state) {
    mState = state;
  }

  /**
   * 释放状态资源
   */
  onRelease() {
    mState.onRelease();
  }

  /**
   * 页面退出
   */
  onUnload() {
    this.disconnect();
    this.onRelease();
  }

  getState() {
    return mState;
  }

  getUnConnectState() {
    return mUnConnectState;
  }

  getConnectingState() {
    return mConnectingState;
  }

  getConnectedState() {
    return mConnectedState;
  }


  getStateId() {
    return mState.getStateId();
  }


  getBLE() {
    if (mBle == null)
      mBle = BLE.getInstance();
    return mBle;
  }

  notifyAll() {
    this.notifyState(mState.getStateId());
  }

  /**
   * 通知页面当前的状态
   * @param {*} status 
   */
  notifyState(status) {
    mPageObservers.forEach((pageObserver) => {
      pageObserver(status);
    });
  }

}

module.exports = StateController

使用新的设计

import State from './state'
import StateController from './StateController'
class StateTest {
  constructor() {}

  onClick() {
    // let state = new State();
    // state.connectBLE();
    let stateController = StateController.getInstance();
    stateController.connect();
  }
}

module.exports = StateTest;

通过新的设计,我们可以看到一些变化:
1.将每个状态的行为局部化到了它自己的类中;
2.去掉了很多的ifelse语言;
3.方便扩展,可增删状态,对每个状态来说是“对修改关闭”。

状态模式定义

状态模式允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它的类。

状态模式类图

在这里插入图片描述

总结

  1. 状态模式用类代表状态;
  2. 使用状态模式会增加类的数目,但这是为了更好的扩展和弹性;
  3. 状态的转换可以由各状态(State)改变,也可以由Context类控制,比如示例中的StateController。

如需转载请注明原地址

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

jjr_1984

谢谢您的鼓励!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值