发布-订阅者(观察者模式)以及 代理模式

Posted 木子喵

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了发布-订阅者(观察者模式)以及 代理模式相关的知识,希望对你有一定的参考价值。

概念

它定义了对象一对多的关系,让多个观察者对象同时监听某一个主题。当依赖的对象发生改变时候,所有依赖于他的对象,都会得到通知

例子

  • 订购双十一购物车。收到短信提示
  • 电话号码留在售楼部花名,订购售楼部开盘信息
  • vue-watch-computed&观察者模式

优点

  • 支持简单的广播通信,当对象状态发生改变时,会自动通知已经订阅过的对象。
  • 发布者与订阅者耦合性降低,发布者只管发布一条消息出去,它不关心这条消息如何被订阅者使用,同时,订阅者只监听发布者的事件名,只要发布者的事件名不变,它不管发布者如何改变

缺点

  • 创建订阅者需要消耗一定的时间和内存。如果过度使用的话,反而使代码不好理解及代码不好维护等等。
  • 比如我们常用的events.

    import EventEmitter from \'events\';
     EventEmitter.addListener(\'ResetjoblistNum\', () => {
        this.pageNum = 1
        this.flag = true
      })
     
     EventEmitter.emit(\'ResetjoblistNum\', \'\') 
      

实战

  • 给发布者添加一个缓存列表,用于存放回调函数来通知订阅者(比如上面的买家收藏了卖家的店铺,卖家通过收藏了该店铺的一个列表名单)。
  • 最后就是发布消息,发布者遍历这个缓存列表,依次触发里面存放的订阅者回调函数。
var Event = (function(){
    var list = {},
          listen,
          trigger,
          remove;
          listen = function(key,fn){
            if(!list[key]) {
                // 如果还没有订阅过此类消息,给该类消息创建一个缓存列表
                list[key] = [];
            }
            list[key].push(fn); // 订阅消息添加到缓存列表
        };
        trigger = function(){
            var key = Array.prototype.shift.call(arguments), // 取出消息类型名称
                 fns = list[key]; // 取出该消息对应的回调函数的集合
            // 如果没有订阅过该消息的话,则返回
            if(!fns || fns.length === 0) {
                return false;
            }
            for(var i = 0, fn; fn = fns[i++];) {
                fn.apply(this,arguments); // arguments 是发布消息时附送的参数
            }
        };
        remove = function(key,fn){
            // 如果key对应的消息没有订阅过的话,则返回
            var fns = list[key];
            // 如果没有传入具体的回调函数,表示需要取消key对应消息的所有订阅
            if(!fns) {
                return false;
            }
            if(!fn) {
                fns && (fns.length = 0);
            }else {
                for(var i = fns.length - 1; i >= 0; i--){
                    var _fn = fns[i];
                    if(_fn === fn) {
                        fns.splice(i,1);// 删除订阅者的回调函数
                    }
                }
            }
        };
        return {
            listen: listen,
            trigger: trigger,
            remove: remove
        }
})();
// 测试代码如下:
Event.listen("color",function(size) {
    console.log("尺码为:"+size); // 打印出尺码为42
});
Event.trigger("color",42);

2.代理模式

一个对象,跟本体对象具有相同的接口,以达到对本地对象的访问控制
本地对象只注重业务逻辑的实现,代理控制本地对象的实例化。

简单的来说

  • 客户-主体
  • 客户-代理-主体

比如广告找明星代言,广告商只能联系他的经纪人,经纪人会把商业演出的细节和报酬谈好了,再把合同给到明星来签署

优点

  • 代理对象可以代替本体对象被实例化,此时本体对象未真正实例化,等到合适时机再实例化。
  • 指责单一
  • 虚拟代理,把开销最大的对象,延迟到真正需要它的时候再做创建
  • 保护代理,AOP 切面思想,先做过滤,再做操作。
// 虚拟代理
var myImage = (function () {
  var imgNode = document.createElement(\'img\')
  document.body.appendChild(imgNode)
  return {
    setSrc: function (src) {
      imgNode.src = src
    },
  }
})()
// 代理模式
var ProxyImage = (function () {
  var img = new Image()
  img.onload = function () {
    setTimeout(() => {
      myImage.setSrc(this.src)
    }, 2000)
  }
  return {
    setSrc: function (src) {
      myImage.setSrc(
        \'http://img.lanrentuku.com/img/allimg/1212/5-121204193R0.gif\'
      )
      img.src = src
    },
  }
})()
export default ProxyImage

以上是关于发布-订阅者(观察者模式)以及 代理模式的主要内容,如果未能解决你的问题,请参考以下文章

观察者模式 vs 发布-订阅模式

JavaScript简单手写观察者模式

基本设计模式

基本设计模式

设计模式Javascript设计模式——订阅发布模式

基本设计模式