
背景
开发复杂H5游戏页面,会涉及到不同的模块,比如,游戏模块、计分模块、展示模块等等。为了降低各个模块开发者之间沟通和维护成本,同时为了应对产品疯狂多变的需求轰炸,我们可以巧妙运用观察者模式实现模块解耦。
实现一个观察者类 eventEmitter.js
class EventEmitter {
constructor() {
this.handlers = {};
}
/**
* 注册事件
* @param {事件名词} eventName
* @param {事件执行} callback
*/
on(eventName, callback) {
if (!this.handlers[eventName]) {
this.handlers[eventName] = [];
}
this.handlers[eventName].push(callback);
}
/**
* 触发事件
* @param {事件名词} eventName
*/
emit(eventName) {
if (this.handlers && this.handlers[arguments[0]]) {
for (var i = 0; i < this.handlers[arguments[0]].length; i++) {
this.handlers[eventName][i].apply(null, [].slice.call(arguments, 1));
}
}
}
/**
* 移除事件
* @param {事件名词} eventName
* @param {事件} callback
*/
remove(eventName, callback) {
if (this.handlers[eventName] instanceof Array) {
const handlers = this.handlers[eventName];
for (let i = 0, len = handlers.length; i < len; i++) {
if (handlers[i] === callback) {
this.handlers[eventName].splice(i, 1);
break;
}
}
}
}
}
export default EventEmitter;
全局观察者
事件名称建议采用 模块-事件 命名
import EventEmitter from './eventEmitter'
window.watcher = new EventEmitter();
// 游戏触发module_a展示
window.watcher.emit('module_a_show', data)
// 模块b监听到模块a展示事件, 触发module_d关闭
window.watcher.on('module_a_show', data => {
// do your thing
window.watcher.emit('module_d_close', data)
})
// 模块c监听到模块a展示事件
window.watcher.on('module_a_show', data => {
// do your thing
})
// 模块d监听到关闭事件
window.watcher.on('module_d_close', data => {
// do your thing
})
如何移除事件
事件必须要用变量保存
const moduleShowSuccess = data => {
}
window.watcher.on('module-show', moduleShowSuccess)
window.watcher.emit('module-show', data)
window.watcher.remove('module-show', moduleShowSuccess)
除了全局观察者,也可以给模块自身添加观察者
import EventEmitter from './eventEmitter'
class Module extends EventEmitter {
constructor() {
super()
}
}
const module = new Module()
module.on('show', data => {})
module.emit('show', data)
看到这里很多人可能会存在疑问,这不是发布订阅模式吗?
虽然两种模式都存在订阅者和发布者(具体观察者可认为是订阅者、具体目标可认为是发布者),但是观察者模式是由具体目标调度的,而发布/订阅模式是统一由调度中心调的,所以观察者模式的订阅者与发布者之间是存在依赖的,而发布/订阅模式则不会。
两种模式都可以用于松散耦合,改进代码管理和潜在的复用。
很多人为了写模式而写模式,其实只要能够提高开发者效率,降低维护成本,叫什么还重要吗?并不是因为有了设计模式才有了套路,是因为套路多了才有了设计模式。