javascript设计模式之订阅者模式

目录
  • 一. 初识代理模式
  • 二. 代理模式的实现思想
  • 三. 代理模式分类
  • 四. 虚拟代理模式的实际运用
  • 五. 代理的使用意义及要求
  • 六. 总结

一. 初识代理模式

代理模式是为一个对象提供一个代用品或占位符,以便控制对它的访问。它的用处就是当客户不方便直接访问一个对象或者不满足需要的时候,提供一个替身对象来控制对这个对象的访问。通俗来讲就是,代理是一个中间人,负责在客户和卖家之间传递信息,将没用的信息过滤,将有利于交易成功的信息传递给卖家,从而加大交易的成功率。

二. 代理模式的实现思想

现在我们来通过一个小明给女神送花的例子来实现代理模式。

没有使用代理模式

        let Flower = function () {};
        let xiaomingFirst = {
            sendFlower ( target ) {
                let flower = new Flower();
                target.receiveFlower( flower );
            }
        }
        let A = {
            receiveFlower ( flower ) {
                console.log('收到花')
            }
        }
        xiaomingFirst.sendFlower(A);

使用代理模式重构

设定一个需求AA 为小明的女神,AA 在心情好的时候接受小明花的几率更大,而 B 是 AA 和小明的好朋友,因此小明将花送给 B,让 B 在 AA 心情好时转告自己的心意。

分析:重构后的代码增加了一个新的对象 B , 此时 为 AA 的代理,监听 AA 的好心情,代码中假定5秒后 AA 心情变好,将花送出。

        let xiaomingSencend = {
            sendFlower ( target ) {
                let flower = new Flower();
                target.receiveFlower( flower );
            }
        }
        let AA = {
            receiveFlower () {
                console.log('收到花');
            },
            listenGoodMood ( fn ) {
                setTimeout(()=>{
                    fn();
                }, 5000);
            }
        }
        let B = {
            receiveFlower ( flower ) {
                AA.listenGoodMood( ()=>{
                    AA.receiveFlower( flower );
                } );
            }
        }
        xiaomingSencend.sendFlower(B);

三. 代理模式分类

上述代码中代理模式可能显得不那么重要,但是体现了代理的思想,假如女神有一些要求,给他送花的男生必须帅而有钱,但又不能显得那么势力,因此代理可以帮其过滤掉这些不符合要求的男生,减少自己的许多麻烦,还能保持自己的美好形象这就是代理的用处。再者说,买一朵花很昂贵,而不是单单 new 这么简单,男生不想浪费自己的钱,因此想先确定女神是否接受自己的花,便让代理帮忙询问,如果女神接受则让代理帮忙买一朵送给女神,这样减少了男生的损失但也达成了目的,这便引出了以下两种代理模式。

  • 保护代理:本体的要求直接在代理中实现,过滤掉不符合的要求的访问者对本体的请求
  • 虚拟代理:将一些开销很大的操作等到准备向本体请求时候再实现(主要用于实际开发)

四. 虚拟代理模式的实际运用

1. 虚拟代理实现图片预加载

分析:先加载本地图片,然后开始发起请求获取图片,当图片加载获取成功后,再调用 myImage 将图片替换预加载时显示的图片。

    let myImage = function () {
        let img = document.createElement('img');
        document.body.appendChild(img);
        return {
            setSrc ( src ) {
                img.src = src;
            }
        }
    }();
    proxyImage = function () {
        let img = new Image;
        img.onload = function () {
            myImage.setSrc( this.src );
        }
        return {
            setProxyImage( src ) {
                myImage.setSrc("https://img.zcool.cn/community/01e2115d5d5c7da80120695c137bfb.jpg@1280w_1l_2o_100sh.jpg"); // 此处为加载 loading 图片,用来占位,本地图片(作者使用网络图片)
                img.src = src;
            }
        }
    }();
    proxyImage.setProxyImage("https://img.zcool.cn/community/01a5d45543cd170000019ae94fc087.jpg@1280w_1l_2o_100sh.jpg");

 2. 缓存代理

分析:在代理中将本体计算的结果进行缓存,如果下次再遇到同样的请求,直接从缓存中获取,减少对本体的访问,减少性能消耗。

        // 计算乘积的函数
        let mult = function (...arg) {
            console.log('我执行了')
            let m = 1;
            for(let i = 0,l = arg.length; i <l; i++){
                m *= arg[i];
            }
            return m;
        }
        // 缓存代理
        let proxyMult = function( fn ) {
            let cache = {};
            return function (...arg) {
                let argS = arg.join(',');
                if( cache[argS] ) {
                    return cache[argS];
                }
                return cache[argS] = fn.apply( this, arg);
            }
        };
        let proxymult = proxyMult(mult);
        console.log(proxymult(1,2,4))

3. 虚拟代理合并 Http 请求

使用场景:点击复选框向服务器发起请求同步文件,每次点击复选框便发起一次请求,造成巨大网络开销,此时我们优化的方式为,将想同步的文件缓存下来,在 3 秒后通过一次请求发送到服务器。

    <input type="checkbox" >1
    <input type="checkbox" >2
    <input type="checkbox" >3
    <input type="checkbox" >4
    <input type="checkbox" >5
    <input type="checkbox" >6
    <input type="checkbox" >7
    <input type="checkbox" >8
    <script>
        // 同步文件
        let synchronousFile = function ( id ) {
            console.log("开始同步文件" + id);
        }
        // 代理实现同步文件
        let proxySynchronousFile = function ( ) {
            let cache = [];
            let time;
            return function ( id ) {
                cache.push( id );
                if( time ) {
                    return;
                }
                time = setInterval(() => {
                    synchronousFile(cache.join(','));
                    clearInterval(time);
                    time = null;
                    cache.length = 0;
                }, 3000);
            }
        }()
        // 添加点击执行
        let checkboxList = document.getElementsByTagName('input');
        for(let i = 0, l = checkboxList.length; i < l; i++) {
            checkboxList[i].onclick = function() {
                if( this.checked === true ) {
                    proxySynchronousFile(i+1);
                }
            }
        }

五. 代理的使用意义及要求

意义:首先我们引入面向对象设计原则,单一职责原则,一个对象应该尽可能少的承担职责,最好是一个,如果承担职责过多,会提高代码的耦合度,从而导致脆弱和低内聚的设计。当变化发生,设计可能遭到意外破坏,即使实现同样需求可以将代码封装到一个函数中,但是最好的处理措施是引入代理模式

要求:代理和本体接口要一致,在任何使用本体地方都可以用代理来代替

六. 总结

代理模式包括很多小模块,最常用的为缓存代理 和 虚拟代理,虽然代理模式非常有用,但我们再编写业务代码时不需要预先猜测是否需要使用代理模式,到发现不方便直接访问某个对象,真正使用时再编写也不迟。

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注我们的更多内容!

(0)

相关推荐

  • 原生js实现的观察者和订阅者模式简单示例

    本文实例讲述了原生js实现的观察者和订阅者模式.分享给大家供大家参考,具体如下: 观察者模式也叫 发布者-订阅者模式,发布者发布事件,订阅者监听事件并做出反应 在传统的前端解耦方面,观察者模式作为比较常见一种设计模式,大量使用在各种框架类库的设计当中. 核心代码: // eventProxy.js 'use strict'; const eventProxy = { onObj: {}, oneObj: {}, on: function(key, fn) { if(this.onObj[key]

  • JavaScript设计模式之观察者模式(发布者-订阅者模式)

    观察者模式( 又叫发布者-订阅者模式 )应该是最常用的模式之一. 在很多语言里都得到大量应用. 包括我们平时接触的dom事件. 也是js和dom之间实现的一种观察者模式. 复制代码 代码如下: div.onclick  =  function click (){ alert ( "click' ) } 只要订阅了div的click事件. 当点击div的时候, function click就会被触发. 那么到底什么是观察者模式呢. 先看看生活中的观察者模式. 好莱坞有句名言. "不要给我

  • [js高手之路]设计模式系列课程-发布者,订阅者重构购物车的实例

    发布者订阅者模式,是一种很常见的模式,比如: 一.买卖房子 生活中的买房,卖房,中介就构成了一个发布订阅者模式,买房的人,一般需要的是房源,价格,使用面积等信息,他充当了订阅者的角色 中介拿到卖主的房源信息,根据手头上掌握的客户联系信息(买房的人的手机号),通知买房的人,他充当了发布者的角色 卖主想卖掉自己的房子,就需要告诉中介,把信息交给中介发布 二,网站订阅信息的用户 订阅者角色:需要订阅某类信息的网民,如某个网站的javascript类型文章 发布者角色:邮箱服务器,根据网站收集到的用户订

  • JS模式之简单的订阅者和发布者模式完整实例

    本文实例讲述了JS模式之简单的订阅者和发布者模式.分享给大家供大家参考.具体如下: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <h

  • javascript设计模式之订阅者模式

    目录 一. 初识代理模式 二. 代理模式的实现思想 三. 代理模式分类 四. 虚拟代理模式的实际运用 五. 代理的使用意义及要求 六. 总结 一. 初识代理模式 代理模式是为一个对象提供一个代用品或占位符,以便控制对它的访问.它的用处就是当客户不方便直接访问一个对象或者不满足需要的时候,提供一个替身对象来控制对这个对象的访问.通俗来讲就是,代理是一个中间人,负责在客户和卖家之间传递信息,将没用的信息过滤,将有利于交易成功的信息传递给卖家,从而加大交易的成功率. 二. 代理模式的实现思想 现在我们

  • JavaScript设计模式发布订阅模式

    目录 前言 发布订阅设计模式 前言 发布订阅设计模式是和观察者设计模式基本上相同,但是他们两个设计模式不同的是发布订阅者拥有一个事件处理中心而观察者并没有 比如,我们利用订阅者设计模式去监听一个对象的改变,可以给对象改变的方法添加多个行为以及一个行为添加多个方法进行处理 发布订阅设计模式 发布订阅设计模式只需要一个类,类中拥有一个事件中心管理这行为的任务对列,我们利用这个构造函数创建一个实例,在进行模拟一个addEventListener()事件,进行触发事件中心行为上任务对列的方法 我们来举一

  • JavaScript设计模式之调停者模式实例详解

    本文实例讲述了JavaScript设计模式之调停者模式.分享给大家供大家参考,具体如下: 1.定义 调停者模式包装了一系列对象相互作用的方式,使得这些对象不必相互明显作用.从而使他们可以松散偶合.当某些对象之间的作用发生改变时,不会立即影响其他的一些对象之间的作用.保证这些作用可以彼此独立的变化.调停者模式将多对多的相互作用转化为一对多的相互作用.调停者模式将对象的行为和协作抽象化,把对象在小尺度的行为上与其他对象的相互作用分开处理. 2.使用的原因 当对象之间的交互操作很多,且每个对象的行为操

  • JavaScript设计模式之中介者模式详解

    目录 中介者模式 现实中的中介者 中介者模式的例子 泡泡堂游戏 为游戏增加队伍 玩家增多带来的困扰 用中介者模式改造泡泡堂游戏 小结 中介者模式 在我们生活的世界中,每个人每个物体之间都会产生一些错综复杂的联系.在应用程序里也是一样,程序由大大小小的单一对象组成,所有这些对象都按照某种关系和规则来通信. 平时我们大概能记住 10 个朋友的电话.30 家餐馆的位置.在程序里,也许一个对象会和其他 10 个对象打交道,所以它会保持 10 个对象的引用.当程序的规模增大,对象会越来越多,它们之间的关系

  • JavaScript设计模式经典之工厂模式

    一.工厂模式概念 工厂模式定义一个用于创建对象的接口,这个接口由子类决定实例化哪一个类.该模式使一个类的实例化延迟到了子类.而子类可以重写接口方法以便创建的时候指定自己的对象类型(抽象工厂). 这个模式十分有用,尤其是创建对象的流程赋值的时候,比如依赖于很多设置文件等.并且,你会经常在程序里看到工厂方法,用于让子类定义需要创建的对象类型. 二.工厂模式的作用和注意事项 模式作用: 1.对象构建十分复杂--我们穿鞋很简单,但是制作鞋子的过程十分复杂 2.需要依赖具体的环境创建不同的实例--工厂可以

  • JavaScript设计模式经典之命令模式

    一.命令模式概念 命令模式(Command)的定义是:用来对方法调用进行参数化处理和传送,经过这样处理过的方法调用可以在任何需要的时候执行.也就是说该模式旨在将函数的调用.请求和操作封装成一个单一的对象,然后对这个对象进行一些列的处理.他也可以用来消除调用操作的对象和实现操作的对象之间的耦合.这为各种具体的类的更换带来了极大的灵活性. 二.命令模式的作用和注意事项 模式作用: 1.将函数的封装.请求.调用结合为一体 2.调用具体的函数解耦命令对象与接收对象 3.提高程序模块化的灵活性 注意事项:

  • JavaScript设计模式之享元模式实例详解

    本文实例讲述了JavaScript设计模式之享元模式.分享给大家供大家参考,具体如下: 通过两个例子的对比来凸显享元模式的特点:享元模式是一个为了提高性能(空间复杂度)的设计模式,享元模式可以避免大量非常相似类的开销. 第一实例,没有使用享元模式,计算所花费的时间和空间使用程度. 要求为:有一个城市要进行汽车的登记 (1)汽车类 /** * 制造商 * 型号 * 拥有者 * 车牌号码 * 最近一次登记日期 */ var Car = function(make,model,year,owner,t

  • JavaScript设计模式之缓存代理模式原理与简单用法示例

    本文实例讲述了JavaScript设计模式之缓存代理模式原理与简单用法.分享给大家供大家参考,具体如下: 一.原理: 缓存代理可以为一些开销大的运算结果提供暂时的存储,在下次运算时,如果传递进来的参数跟之前的一致,则可以直接返回前面存储的运算结果,提供效率以及节省开销. 二.实例: var mult = function(){ console.log('开始计算乘机'); var a = 1; for(var i = 0, l = arguments.length;i < l;i++){ a =

  • 详解javascript设计模式三:代理模式

    代理模式是一种对程序对象进行控制性访问的一类解决方案. 引入代理模式,其实是为了实现单一职责的面向对象设计原则. 单一职责其实就是指在一个类中(js中通常指对象和函数等),应仅有一个引起它变化的原因.这样会帮助程序设计具有良好的健壮和高内聚特性,从而当变化发生时,程序设计会尽量少的受到意外破坏. 代理模式有多种方法,保护代理.远程代理.虚拟代理.缓存代理等. 但在javascript中,代理模式最常用到的两种方法是虚拟代理和缓存代理. 虚拟代理 在理解虚拟代理时,可以将其想象为一个经纪人,客户程

  • JavaScript设计模式之职责链模式应用示例

    本文实例讲述了JavaScript设计模式之职责链模式.分享给大家供大家参考,具体如下: 一.职责链的定义: 使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系,将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止. 二.实例场景说明: 某公司对公司产品-手机进行促销活动,有以下政策:在正式购买时,已经支付过500元定金的用户会收到100元的商城优惠卷,交200元定金的用户可以收到50元的优惠卷,而之前没有支付定金的用户只能进入普通购买模式,也就是没有优惠卷

随机推荐