2019-06-26

常用的设计模式

作为一个前端 开发者,如果不懂几种常见的设计模式的话就感觉有点说不过去了。现在用的最多最广的设计模式就是发布订阅模式和观察者模式。严格来讲,这两种模式都可以归于观察者模式。下面就来分别介绍一下发布订阅模式和观察者模式。

发布订阅模式

说到发布订阅模式,它的最基本的功能就是能够订阅事件,能够发布事件,我们也可以衍生出一些其他事件,比如竟然能够订阅事件,也应该能够 移除事件等等。大家要记住,发布订阅的一个特点就是发布和订阅没有关系,它们两个是依赖一个中间件(类似于代理)来完成交流。正是因为它的这个特点,我们写起来就更加的容易。下面来实现一个功能比较完整的发布订阅的例子:

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] = []);
   }
}
image.png

这个里面的中间件就是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("心情又变好了")//改变状态,同时通知所有观察者
image.png

我们常见的vue,mobx等等都是基于观察者模式实现的,大家一定要仔细体会一下,这对我们有很大帮助。技术比较扎实的同学推荐去找一下相关的源码来研究一下。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。