通过例子理解观察者模式和发布订阅模式的区别
观察者模式 Subject 是一个主题,Observer 是一个观察者。观察者可以订阅主题,主题发生变化会通知观察者。这是一个典型的观察者模式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 class Subject { constructor () { this .subs = [] } subscribe(sub) { this .subs.push(sub) } unsubscribe(sub) { const index = this .subs.indexOf(sub) if (index > -1 ) { this .subs.splice(index, 1 ) } } fire() { this .subs.forEach(sub => { sub.notify() }) } } class Observer { constructor (data) { this .data = data } notify() { console .log(this .data) } } let subject = new Subject()let ob1 = new Observer('hello' )let ob2 = new Observer('world' )subject.subscribe(ob1) subject.subscribe(ob2) subject.fire()
DOM 事件中的观察者模式,这里回调函数就是一个观察者,订阅了 body 的 click 事件。所以当 body 触发 click 时,会触发回调。
1 2 3 4 5 6 7 document .body.addEventListener( 'click' , function (e ) { console .log('click body' ) }, false )
修改观察者模型,用 Dom 模拟上述例子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 class Dom { constructor () { this .events = {} } addEventListener(event, callback) { if (!this .events[event]) { this .events[event] = [] } this .events[event].push(callback) } removeEventListener(event, callback) { if (!this .events[event]) { return } const callbackList = this .events[event] const index = callbackList.indexOf(callback) if (index > -1 ) { callbackList.splice(index, 1 ) } } fireEvent(event) { if (!this .events[event]) { return } this .events[event].forEach(callback => { callback() }) } } const handler = () => { console .log('fire click' ) } const dom = new Dom()dom.addEventListener('click' , handler) dom.addEventListener('move' , function ( ) { console .log('fire click2' ) }) dom.fireEvent('click' )
发布订阅模式 与观察者模式相比,发布订阅模式中间多了一层处理机制,用于解耦发布者和订阅者之间的关联
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 class EventChannel { constructor () { this .subjects = {} } hasSubject(subject) { return this .subjects[subject] ? true : false } on(subject, callback) { if (!this .hasSubject(subject)) { this .subjects[subject] = [] } this .subjects[subject].push(callback) } off(subject, callback) { if (!this .hasSubject(subject)) { return } const callbackList = this .subjects[subject] const index = callbackList.indexOf(callback) if (index > -1 ) { callbackList.splice(index, 1 ) } } emit(subject, ...data) { if (!this .hasSubject(subject)) { return } this .subjects[subject].forEach(callback => { callback(...data) }) } } const channel = new EventChannel()channel.on('update' , function (data ) { console .log(`update value: ${data} ` ) }) channel.emit('update' , 123 )
这里通过 emit 向主题 update 发布一条消息, 在通过 on 来订阅 update 的主题来接受消息。
参考