Node.js 设计模式笔记 —— State 模式

2022-07-18  本文已影响0人  rollingstarky

State 模式是一种特殊形式的 Strategy 模式:Context 选择的具体策略根据不同的 state 发生变化。
对于 Strategy 模式,可以基于不同的变量比如传入的参数来决定选择具体哪个策略,一旦选择确定后,直到 context 剩余的整个生命周期结束,该策略都保持不变。相反在 State 模式中,策略(或者在这里的语境下,叫做状态)在 context 的生命周期里是动态变化的,从而允许对象的行为可以根据内部状态的变化自适应地更改。

State pattern

举例来说,我们需要创建一个宾馆预定系统,由一个 Reservation 类对预定房间的行为进行建模。

考虑如下一系列事件:

State pattern

参考上图,可以实现 3 种 不同的策略,他们都实现了 confirm()cancel()delete() 这几个方法。每种策略的具体逻辑由不同的状态决定。Reservation 对象只需要在每次状态切换时,激活对应的策略。

实例:failsafe socket

mkdir state && cd state
npm install json-over-tcp-2

package.json

{
  "type": "module",
  "dependencies": {
    "json-over-tcp-2": "^0.3.5"
  }
}

failsafeSocket.js

import {OfflineState} from './offlineState.js'
import {OnlineState} from './onlineState.js'

export class FailsafeSocket {
  constructor(options) {
    this.options = options
    this.queue = []
    this.currentState = null
    this.socket = null
    this.states = {
      offline: new OfflineState(this),
      online: new OnlineState(this)
    }
    this.changeState('offline')
  }

  changeState(state) {
    console.log(`Activating state: ${state}`)
    this.currentState = this.states[state]
    this.currentState.activate()
  }

  send(data) {
    this.currentState.send(data)
  }
}

上述 FailsafeSocket 类主要由以下几个组件构成:

offlineState.js

import jsonOverTcp from 'json-over-tcp-2'

export class OfflineState {
  constructor(failsafeSocket) {
    this.failsafeSocket = failsafeSocket
  }

  send(data) {
    this.failsafeSocket.queue.push(data)
  }

  activate() {
    const retry = () => {
      setTimeout(() => this.activate(), 1000)
    }

    console.log('Trying to connect...')
    this.failsafeSocket.socket = jsonOverTcp.connect(
      this.failsafeSocket.options,
      () => {
        console.log('Connection established')
        this.failsafeSocket.socket.removeListener('error', retry)
        this.failsafeSocket.changeState('online')
      }
    )
    this.failsafeSocket.socket.once('error', retry)
  }
}

上述模块负责定义 socket 处于离线状态时的行为。

onlineState.js

export class OnlineState {
  constructor(failsafeSocket) {
    this.failsafeSocket = failsafeSocket
    this.hasDisconnected = false
  }

  send(data) {
    this.failsafeSocket.queue.push(data)
    this._safeWrite(data)
  }

  _safeWrite(data) {
    this.failsafeSocket.socket.write(data, (err) => {
      if (!this.hasDisconnected && !err) {
        this.failsafeSocket.queue.pop()
      }
    })
  }

  activate() {
    this.hasDisconnected = false
    for (const data of this.failsafeSocket.queue) {
      this._safeWrite(data)
    }

    this.failsafeSocket.socket.once('error', () => {
      this.hasDisconnected = true
      this.failsafeSocket.changeState('offline')
    })
  }
}

OnlineState 模块实现了当 socket 处于在线状态时的行为。

server.js

import jsonOverTcp from 'json-over-tcp-2'

const server = jsonOverTcp.createServer({port: 5000})
server.on('connection', socket => {
  socket.on('data', data => {
    console.log('Client data', data)
  })
})

server.listen(5000, () => console.log('Server started'))

client.js

import {FailsafeSocket} from './failsafeSocket.js'

const failsafeSocket = new FailsafeSocket({port: 5000})
setInterval(() => {
  failsafeSocket.send(process.memoryUsage())
}, 1000)

参考资料

Node.js Design Patterns: Design and implement production-grade Node.js applications using proven patterns and techniques, 3rd Edition

上一篇 下一篇

猜你喜欢

热点阅读