为了账号安全,请及时绑定邮箱和手机立即绑定

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()
点击查看更多内容
1人点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消