• JavaScript面试系列:JavaScript设计模式之桥接模式和懒加载


    我写的程序员面试系列文章

    Java面试系列-webapp文件夹和WebContent文件夹的区别?

    程序员面试系列:Spring MVC能响应HTTP请求的原因?

    Java程序员面试系列-什么是Java Marker Interface(标记接口)

    使用JDK自带的工具jstack找出造成运行程序死锁的原因

    编程面试题:编写一个会造成数据库死锁的应用

    JavaScript面试系列:JavaScript设计模式之桥接模式和懒加载

    设计模式(Design Pattern)中的桥接模式,有的朋友平时工作可能很少用到。桥接模式的核心在于将抽象部分和它的实现部分分离,使它们都可以独立的变化。听起来很抽象,让我们看一个具体而简单的例子,通过这个例子一步步的完善来加深对桥接模式的理解。

    很多论坛点登录按钮时,

    周围背景都会暗下来,这样可以突出即将弹出的登录框,让用户把精力集中在用户名和密码的输入上去。

    很多论坛对于这种背景变暗的UI实现,是创建了一个HTML原生的div元素,加上一些精心设计过背景颜色的CSS样式来完成的。

    我们下面称这种div元素为遮罩层div元素,即mask div。

    下面讨论创建mask div的最优解。

    实现版本1

    创建一个createMask函数,作为登录按钮的事件响应函数。每次点击按钮之后执行该函数。

    var createMask = function(){
    
          return document.body.appendChild( document. createElement('div') );
    
    }
    
    $(‘#logon_button').click(function(){
    
        var mask = createMask();
    
        mask.show();
    
    })
    

    版本1的缺点

    每次点击按钮都会创建一个mask div。当然一般情况下登录按钮只会点击一次。但是在面试场景中,面试官可能会把这个问题的讨论引导到其他方向上。如何实现即使多次点击按钮,也只会创建一次mask div?于是就有了版本2。

    实现版本2

    事先创建好一个mask div,放到一个全局变量里保存。这种方式有点像单例模式(singleton)的饿汉式单例。

    var mask = document.body.appendChild(document.createElement('div' ) );
    
    $( '#logon_button').click(function(){
    
         mask.show();
    
    })
    

    版本2的缺点

    版本2采用了一个全局变量保存事先创建好的mask div。还记得那句话么?全局变量是万恶之源。

    另外,假设用户永远不点登录按钮,只是以游客身份浏览网站,那么这个mask div就白白创建了。

    实现版本3

    
    var mask;
    
    var createMask = function(){
    
      if(mask)
    
            return mask;
    
      else{
    
            mask = document,body.appendChild( document.createElement('div') );
    
    return mask;
    
    }
    
    }
    

    版本3的缺点

    虽然使用了饱汉式单例模式,避免了mask div在没有点击登录按钮的情况下不必要的创建,但还是使用了全局变量来存放mask div。要记住我们现在是在用JavaScript,因此可以用它提供的强大的闭包特性(closure)来实现不需要全局变量的饱汉式单例模式。

    实现版本4

    var createMask = function() {
    
       var mask;
    
       return function() {
    
           return mask || ( mask = document.body.appendChild(document.createElement('div')));
    
    }
    
    }();
    

    借助JavaScript的闭包特性,我们在第二行创建的自由变量(Free variable)只在闭包内部可见,外部消费者感知不到这个变量,因此成为存储mask div的最佳选择。看起来这个版本已经很完美了?不,它仍然有可以优化的空间,即题目提到的桥接模式。

    版本4的缺点

    从单一职责原理(Single Responsibility)来衡量版本4,createMask函数里实际包含了两种不同类型的逻辑:

    1. 创建mask div

    2. 使该mask div “单例化”

    我们下面使用桥接模式将这两种逻辑分开,来实现最终版本。

    使用桥接模式的实现版本5

    这个实现包含了三个JavaScript函数。首先看singleton函数。

    函数singleton的输入参数是另一个JavaScript函数(我称其为原始函数),输出是一个包装后的函数,其内部使用闭包,将原始函数第一次执行的结果保存在闭包内,当包装后的函数第二次执行时,直接返回闭包内保存的第一次执行结果。我们可以把singleton函数当成一个构造器,传入任意一个具有返回值的JavaScript函数,负责生产出具有“单例化”特性的新函数。

    var singleton = function(fn){
    
       var result;
    
       return function() {
    
            return result || ( result = fn.apply(this,arguments));
    
       }
    
    }
    
    var origin = function(){
    
          return document.body.appendChild(document.createElement('div'));
    
    };
    
    var createMask = singleton(origin);
    

    然后我们调用这个singleton函数,把我们原始的创建mask div的函数origin作为参数传进去,得到加工后的新函数createMask。

    这个例子体现了桥接模式的作用。我们通过singleton这个单例化构造器函数,成功将业务逻辑(创建mask div)和单例化这个纯技术需求分离开,这样也满足了单一职责(single responsibility)的设计理念。

    要获取更多Jerry的原创技术文章,请关注公众号"汪子熙"或者扫描下面二维码:

  • 相关阅读:
    ABBYY FineReader 12如何识别包含非常规符号的文本
    如何使用ABBYY FineReader 12将JPEG文件转换成可编辑文本
    如何使用ABBYY FineReader 12将JPEG文件转换成Word文档
    ABBYY OCR技术教电脑阅读缅甸语(下)
    ABBYY OCR技术教电脑阅读缅甸语(上)
    ABBYY FineReader 12使用教程
    ABBYY FineReader Pro for Mac有哪些特性(下)
    ABBYY FineReader Pro for Mac有哪些特性(上)
    MyBatis foreach
    callback 回调函数
  • 原文地址:https://www.cnblogs.com/sap-jerry/p/9818903.html
Copyright © 2020-2023  润新知