javascript设计模式之行为型模式
观察者
- 发布&订阅
- 一对多
- 验证
- 主题和观察者分离,不是主动触发而是被动监听,两者解耦
- 符合开放封闭原则
- 示例
- 点餐,等餐
- 场景
- 网页事件绑定
- Promise
- .then的多次调用
- jQuery callbacks
– - nodejs 自定义事件
- 处理http请求;多进程通讯
- vue watch
- vue,react 生命周期触发
- 网页事件绑定
// 主题,接收状态变化,触发每个观察者
class Subject {
constructor() {
this.state = 0
this.observers = []
}
getState() {
return this.state
}
setState(state) {
this.state = state
this.notifyAllObservers()
}
attach(observer) {
this.observers.push(observer)
}
notifyAllObservers() {
this.observers.forEach(observer => {
observer.update()
})
}
}
// 观察者,等待被触发
class Observer {
constructor(name, subject) {
this.name = name
this.subject = subject
this.subject.attach(this)
}
update() {
console.log(`${this.name} update, state: ${this.subject.getState()}`)
}
}
// 测试代码
let s = new Subject()
let o1 = new Observer('o1', s)
let o2 = new Observer('o2', s)
let o3 = new Observer('o3', s)
s.setState(1)
s.setState(2)
s.setState(3)
nodejs
const EventEmitter = require('events').EventEmitter
// const emitter1 = new EventEmitter()
// emitter1.on('some', () => {
// // 监听 some 事件
// console.log('some event is occured 1')
// })
// emitter1.on('some', () => {
// // 监听 some 事件
// console.log('some event is occured 2')
// })
// // 触发 some 事件
// emitter1.emit('some')
// const emitter = new EventEmitter()
// emitter.on('sbowName', name => {
// console.log('event occured ', name)
// })
// emitter.emit('sbowName', 'zhangsan') // emit 时候可以传递参数过去
// 任何构造函数都可以继承 EventEmitter 的方法 on emit
class Dog extends EventEmitter {
constructor(name) {
super()
this.name = name
}
}
var simon = new Dog('simon')
simon.on('bark', function () {
console.log(this.name, ' barked')
})
setInterval(() => {
simon.emit('bark')
}, 500)
文件流式读取steam
var fs = require('fs')
var readStream = fs.createReadStream('./data/file1.txt') // 读取文件的 Stream
var length = 0
readStream.on('data', function (chunk) {
length += chunk.toString().length
})
readStream.on('end', function () {
console.log(length)
})
var readline = require('readline');
var fs = require('fs')
var rl = readline.createInterface({
input: fs.createReadStream('./data/file1.txt')
});
var lineNum = 0
rl.on('line', function(line){
lineNum++
});
rl.on('close', function() {
console.log('lineNum', lineNum)
});
迭代器
- 顺序访问一个集合
- 使用者无需知道集合的内部结构(封装)
- 验证
- 迭代器对象和目标对象分离
- 迭代器将使用者与目标对象隔离开
- 符合开放封闭原则
- 场景
- jQuery each
- ES6 Iterator
- ES6语法中,有序集合的数据类型已经有很多
- Array Map Set String TypedArray arguments NodeList
- 需要有一个统一的遍历接口来遍历所有数据类型
- (注意,object 不是有序集合,可以用Map代替)
- 以上数据类型,都有[Symbol.iterator]属性
- 属性值是函数,执行函数返回一个迭代器
- 这个迭代器就有next 方法可顺序迭代子元素
- 可运行Array.prototype[Symbol.iterator]来测试
- Iterator的价值不限于上述几个类型的遍历
- 还有Generator 函数的使用
- 即只要返回的数据符合Iterator 接口的要求
- jquery
UML类图
class Iterator {
constructor(conatiner) {
this.list = conatiner.list
this.index = 0
}
next() {
if (this.hasNext()) {
return this.list[this.index++]
}
return null
}
hasNext() {
if (this.index >= this.list.length) {
return false
}
return true
}
}
class Container {
constructor(list) {
this.list = list
}
getIterator() {
return new Iterator(this)
}
}
// 测试代码
let container = new Container([1, 2, 3, 4, 5])
let iterator = container.getIterator()
while(iterator.hasNext()) {
console.log(iterator.next())
}
let arr = [1, 2, 3, 4]
let nodeList = document.getElementsByTagName('p')
let m = new Map()
m.set('a', 100)
m.set('b', 200)
// function each(data) {
// // 生成遍历器
// let iterator = data[Symbol.iterator]()
// // console.log(iterator.next()) // 有数据时返回 {value: 1, done: false}
// // console.log(iterator.next())
// // console.log(iterator.next())
// // console.log(iterator.next())
// // console.log(iterator.next()) // 没有数据时返回 {value: undefined, done: true}
// let item = {done: false}
// while (!item.done) {
// item = iterator.next()
// if (!item.done) {
// console.log(item.value)
// }
// }
// }
function each(data) {
for (let item of data) {
console.log(item)
}
}
each(arr)
each(nodeList)
each(m)
状态模式
- 一个对象有状态变化
- 每次状态变化都会触发一个逻辑
- 不能总是用if…else来控制
- 验证
- 将状态对象和主题对象分离,状态的变化逻辑单独处理
- 符合开放封闭原则
- 示例
- 交通信号灯不同颜色的变化
- 场景
- 有限状态机
- 有限个状态、以及在这些状态之间的变化
- 如交通信号灯
- 使用开源lib:javascript-state-machine
- Promise
- Promise 三种状态:pending fullfilled rejected
- pending->fullflled 或者pending->rejected
- 不能逆向变化
- 有限状态机
class State {
constructor(color) {
this.color = color
}
handle(context) {
console.log(`turn to ${this.color} light`)
context.setState(this)
}
}
class Context {
constructor() {
this.state = null
}
setState(state) {
this.state = state
}
getState() {
return this.state
}
}
// 测试代码
let context = new Context()
let greed = new State('greed')
let yellow = new State('yellow')
let red = new State('red')
// 绿灯亮了
greed.handle(context)
console.log(context.getState())
// 黄灯亮了
yellow.handle(context)
console.log(context.getState())
// 红灯亮了
red.handle(context)
console.log(context.getState())
状态机模型
// 状态机模型
var fsm = new StateMachine({
init: '收藏', // 初始状态,待收藏
transitions: [
{
name: 'doStore',
from: '收藏',
to: '取消收藏'
},
{
name: 'deleteStore',
from: '取消收藏',
to: '收藏'
}
],
methods: {
// 执行收藏
onDoStore: function () {
alert('收藏成功')
updateText()
},
// 取消收藏
onDeleteStore: function () {
alert('已取消收藏')
updateText()
}
}
})
var $btn = $('#btn')
// 点击事件
$btn.click(function () {
if (fsm.is('收藏')) {
fsm.doStore(1)
} else {
fsm.deleteStore()
}
})
// 更新文案
function updateText() {
$btn.text(fsm.state)
}
// 初始化文案
updateText()
相关文章