Node.js 设计模式笔记 —— State 模式
source link: https://rollingstarky.github.io/2022/07/18/node-js-design-patterns-state-pattern/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
Node.js 设计模式笔记 —— State 模式
State 模式是一种特殊形式的 Strategy 模式:Context 选择的具体策略根据不同的 state 发生变化。
对于 Strategy 模式,可以基于不同的变量比如传入的参数来决定选择具体哪个策略,一旦选择确定后,直到 context 剩余的整个生命周期结束,该策略都保持不变。相反在 State 模式中,策略(或者在这里的语境下,叫做状态)在 context 的生命周期里是动态变化的,从而允许对象的行为可以根据内部状态的变化自适应地更改。
举例来说,我们需要创建一个宾馆预定系统,由一个 Reservation 类对预定房间的行为进行建模。
考虑如下一系列事件:
- 当 reservation 对象初次创建后,其处于未确认状态。用户可以通过一个
confirm()
方法对此次预定进行确认。但不能通过cancel()
方法取消预订,因为此次预定还并没有被确认。可以使用delete()
方法删除这条记录 - 一旦该 reservation 被确认,订单处于已确认状态。
confirm()
方法将不能再次被调用(不能重复确认);但该 reservation 支持通过cancel()
方法进行取消,同时该记录无法被删除(已经有人确认预定) - 在 reservation 日期的前一天,订单处于已生效状态。上述所有 3 个方法都不再支持,用户只能办理入住
参考上图,可以实现 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
类主要由以下几个组件构成:
- 构造函数
constructor
会初始化一个queue
队列来存储 socket 离线时发送的数据,还创建了offline
和online
两种不同的状态,分别对应离线时和在线时 socket 的不同行为 changeState()
方法负责不同状态的切换。它会更新当前状态currentState
并调用该状态的activate()
方法send()
方法包含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 处于离线状态时的行为。
send()
方法只负责将接受到的数据存储到队列中,因为此时是离线状态,队列中的数据会在 socket 在线时取出并发送activate()
方法会尝试建立连接,连接失败则隔一秒重试。成功建立连接后,failsafeSocket
的状态变为在线状态,触发在线状态的activate()
方法
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 处于在线状态时的行为。
send()
方法会将数据放入队列,并立即尝试将其写入到 socket,因为此时是在线状态。若该数据成功写入,则将其从队列中移除activate()
方法会在连接成功建立时触发,会尝试发送在 socket 离线时排队的所有数据并监听任意错误事件。若有错误发生,转换到离线状态,触发离线状态的activate
方法,继续尝试建立连接
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)
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK