优秀的编程知识分享平台

网站首页 > 技术文章 正文

javascript设计模式之行为型模式(js常见设计模式)

nanyue 2024-10-02 17:38:58 技术文章 4 ℃

观察者

  • 发布&订阅
  • 一对多
  • 验证
  • 主题和观察者分离,不是主动触发而是被动监听,两者解耦
  • 符合开放封闭原则
  • 示例
  • 点餐,等餐
  • 场景



  • 处理http请求;多进程通讯


  • .then的多次调用


  • 网页事件绑定
  • Promise
  • jQuery callbacks
  • -

  • nodejs 自定义事件
  • 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)
});

迭代器

  • 顺序访问一个集合
  • 使用者无需知道集合的内部结构(封装)
  • 验证
  • 迭代器对象和目标对象分离
  • 迭代器将使用者与目标对象隔离开
  • 符合开放封闭原则
  • 场景
  • ES6语法中,有序集合的数据类型已经有很多
  • Array Map Set String TypedArray arguments NodeList
  • 需要有一个统一的遍历接口来遍历所有数据类型
  • (注意,object 不是有序集合,可以用Map代替)
  • 以上数据类型,都有[Symbol.iterator]属性
  • 属性值是函数,执行函数返回一个迭代器
  • 这个迭代器就有next 方法可顺序迭代子元素
  • 可运行Array.prototype[Symbol.iterator]来测试
  • Iterator的价值不限于上述几个类型的遍历
  • 还有Generator 函数的使用
  • 即只要返回的数据符合Iterator 接口的要求


  • jQuery each
  • ES6 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来控制
  • 验证
  • 将状态对象和主题对象分离,状态的变化逻辑单独处理
  • 符合开放封闭原则
  • 示例
  • 交通信号灯不同颜色的变化
  • 场景
  • Promise 三种状态:pending fullfilled rejected
  • pending->fullflled 或者pending->rejected
  • 不能逆向变化
  • 有限个状态、以及在这些状态之间的变化
  • 如交通信号灯
  • 使用开源lib:javascript-state-machine


  • 有限状态机
  • Promise
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()

作者:侠客岛的含笑

来源:慕课网,转载请后台联系

Tags:

最近发表
标签列表