常用的设计模式
作为一个前端 开发者,如果不懂几种常见的设计模式的话就感觉有点说不过去了。现在用的最多最广的设计模式就是发布订阅模式和观察者模式。严格来讲,这两种模式都可以归于观察者模式。下面就来分别介绍一下发布订阅模式和观察者模式。
发布订阅模式
说到发布订阅模式,它的最基本的功能就是能够订阅事件,能够发布事件,我们也可以衍生出一些其他事件,比如竟然能够订阅事件,也应该能够 移除事件等等。大家要记住,发布订阅的一个特点就是发布和订阅没有关系,它们两个是依赖一个中间件(类似于代理)来完成交流。正是因为它的这个特点,我们写起来就更加的容易。下面来实现一个功能比较完整的发布订阅的例子:
class EventEmitter {
constructor() {
this.events = {};
}
//获得所有订阅事件
getEvents() {
return this.events;
}
//只执行一次的订阅事件,执行玩不会被清除掉
once(eventName, listener) {
return this.on(eventName, listener, 0);
}
//订阅事件
on(eventName, listener, timer = -1) {
let listeners = this.getListeners(eventName);
listeners.push({
listener,
timer
});
}
//发布事件
emit(eventName, ...args) {
return this.trigger(eventName, args);
}
//移除事件
remove(eventName) {
this.events[eventName] && delete this.events[eventName];
}
//移除事件和事件回调函数
off(eventName, listener) {
let listeners = this.getListeners(eventName);
let index = listeners.findIndex(item => item.listener === listener);
index !== -1 && listeners.splice(index, 1);
}
//配合emit
trigger(eventName, args) {
let listeners = this.getListeners(eventName);
for (let i = 0; i < listeners.length; i++) {
let listener = listeners[i];
if (listener) {
listener.listener.apply(this, args || []);
listener.timer === 0 && listeners.splice(i, 1);
listeners.length === 0 && delete this.events[eventName];
listener.timer !== -1 && listener.timer--;
}
}
}
//获得事件名下面的相关信息
getListeners(eventName) {
return this.events[eventName] || (this.events[eventName] = []);
}
}
这个里面的中间件就是this.events,你可以发现发布与订阅没有什么关系,都是通过this.event这个中间件来交流。我们常用的promise,redux都是基于发布订阅模式封装的,大家感兴趣的话可以去找源码看一下。我个人推荐的一种发布订阅的方式是结合socket使用。封装一个socket类,在进入页面的时候用On方法订阅相关事件,在socket推送的时候使用Emit方法触发订阅的事件,这样就可以很方便的就实现一个实时推送的效果,而不用在每个页面都使用一次socket。
观察者模式
发布订阅模式是观察者模式的一种特殊情况。特殊在哪呢,发布与订阅没有什么关系,它们两个主要是依赖中间代理。而观察者模式顾名思义肯定要有观察者和被观察者,而且观察者必须要放到被观察者里面,只有这样,被观察者发生改变后才能通知到所有的观察者。分析一下观察者模式如何来写,首先要有观察者和被观察者,被观察者里面要有一个添加观察者的方法,同时也要有一个改变状态的方法。被观察者里面要有一个接收到状态变化后要触发的方法,下面简单的实现一下观察者模式:
class Subject{
constructor(name){
this.name=name;
this.observers=[];//观察者需要被添加到被观察者里面,以便状态变化去通知
this.state="心情很高兴"
}
//添加观察者
attach(obj){
this.observers.push(obj);
}
//更改被观察者的状态
setState(newState){
this.state=newState;
this.observers.forEach(v => v.update(newState)) //通知观察者有新状态了
}
}
class Observer{
constructor(name){
this.name=name;
}
//接收到状态变化,更新相关页面
update(data){
console.log(this.name+':你的孩子'+data)
}
}
var s1=new Subject('小孩') //被观察者
var o1=new Observer('爸爸') //观察者
var o2=new Observer('妈妈') //观察者
s1.attach(o1); //加入观察者
s1.attach(o2);//加入观察者
s1.setState("心情不好了") //改变状态,同时通知所有观察者
s1.setState("心情又变好了")//改变状态,同时通知所有观察者
我们常见的vue,mobx等等都是基于观察者模式实现的,大家一定要仔细体会一下,这对我们有很大帮助。技术比较扎实的同学推荐去找一下相关的源码来研究一下。