小议javascript设计模式(3)

作者:oldfish 来源:alipay UED 时间:2009-10-09 13:31:00 

Javascript设计模式之工厂模式Factory

工厂模式Factory:先创建一个抽象类,然后基于这个抽象类派生出子类,并在子类中创建工厂方法,从而把实例化推迟到对应的子类中进行,说实话,工厂模式在javascript中的应用有些牵强,毕竟javascript不像java存在硬编码带来的困搅,要学习的只是模式的思想,切忌因为模式而模式。

不妨举个偏激点的例子,为tab切换、下拉列表等组件添加定位,渐隐,延迟等效果,我们可以先为这些组件定义一个接口:

  var Iwidget = new Interface("iwidget",[["addEffect"]]);

定义该接口,以便之后派生的子类继承,接口中定义了一个addEffect方法,接口方法实现后,调用的同学大可不必关注各子类中对于addEffect方法的代码实现。

var Widget = function(){}; 
    Widget.prototype={ 
      fire:function(model){ 
          var widget = this.createWidget(model); 
          //有同学问为什么子类都必须定义接口方法,因为下面要调用嘛 
          widget.addEffect(); 
          return widget; 
      }, 
      show:function(){ 
        //show代码具体实现  
      }, 
      hide:function(){ 
        //hide代码具体实现  
      }, 
      createWidget:function(model){ 
        alert('抽象类,不可以实例化')  
      } 
    };

上例先定义一个抽象类Widget,做为派生子类的父类,由于考虑到这两类组件都涉及到隐藏和显示一个容器,所以在父类中预先定义好show和hide方法以便子类继承。

var xTab = function(){}; 
    extend(xTab,Widget); 
    xTab.prototype.createWidget = function(model){ 
      var widget; 
      switch(model){ 
        case 'position': 
        widget = new xTabPosition(); 
        break; 
        case 'anim': 
        widget = new xTabAnim(); 
        break; 
        case 'delay': 
        default: 
        widget = new xTabDelay(); 
      } 
    };

var dropDown = function(){}; 
    extend(dropDown,Widget); 
    dropDown.prototype.createWidget = function(model){ 
      var widget; 
      switch(model){ 
        case 'position': 
        widget = new dropDownPosition(); 
        break; 
        case 'anim': 
        widget = new dropDownAnim(); 
        break; 
        case 'delay': 
        default: 
        widget = new dropDownDelay(); 
      } 
    };

子类xTab和dropDown继承了父类,并且重写了createWidget方法,不同的子类根据定位,渐隐,延迟效果分别创建不同的实例,只要创建这些实例的类都实现接口中约定的addEffect方法,至于方法代码如何实现,千篇一律,爱咋整咋整。

var xTabPosition = function(){}; 
    xTabPosition.prototype ={ 
      addEffect:function(){ 
        //具体实现代码  
      } 
    }; 
    var dropDownPosition = function(){}; 
    dropDownPosition.prototype ={ 
      addEffect:function(){ 
        //具体实现代码  
      } 
    }; 
    var dropDownInstance = new dropDown(); 
    dropDownInstance.fire('position');

以此类推,如果您需要为气泡组件添加这些效果,照葫芦画瓢就可以了,说到这里你可以清楚的看到,这种设计模式大大降低了类和类之间的耦合度,而且可以根据具体的交互需求,实现不同的辅助动作,但是也无可避免的增加了代码实现上的复杂性,事实上这种模式并不适合javascript,毕竟它有别于java,不会有类名硬编码的问题,目的是学习他的设计思想,所以以上示例仅供参考,如无大人在旁,小朋友切勿效仿。

对于javascript爱好者来说,更有价值的应该是工厂模式中讲到的的”缓存(memoization)机制”,书上举了个创建XHR对象的例子来说明该特性,但是效果显然不够明显……

memoization名词解释:把函数的每次执行结果都放入一个键值对(数组也可以,视情况而定)中,在接下来的执行中,在键值对中查找是否已经有相应执行过的值,如果有,直接返回该值,没有才 真正执行函数体的求值部分。很明显,找值,尤其是在键值对中找值,比执行函数快多了

在递归调用的时候,memoization的威力才能更好的显现。下面是一个经典的斐波纳契序列,fib(20) 会把fib这个方法执行21891次,如果是fib(40),这会执行331160281次。

function fib(n) {  
    if (n < 2) {  
     return n; 
    }  
     return fib(n - 1) + fib(n - 2); 
    }

再看看如何使用memoization来实现:

var iterMemoFib = (function() {  
    var cache = [1, 1]; 
    var fib = function(n) {  
        if (n >= cache.length) {  
            //将一个递归转换成了一个 
            for (var i = cache.length; i <= n; i++) {  
                cache[i] = cache[i - 2] + cache[i - 1]; 
            }  
        }  
        return cache[n-1]; 
    }  
    return fib; 
   })();

将Function的原型扩展memoize 和unmemoize 方法,这样你可以对任何函数实现memoize和解除memoize,当然,这个方法要慎,对一些不是频繁执行的函数,没必要缓存:

Function.prototype.memoize = function() {  
    var pad  = {}; 
    var self = this; 
    var obj  = arguments.length > 0 ? arguments[i] : null; 
  
    var memoizedFn = function() {  
        // 把参数作为数组保存,作为键,把函数执行的结果作为值缓存起来 
        var args = []; 
        for (var i = 0; i < arguments.length; i++) {  
            args[i] = arguments[i]; 
        }  
        if (!(args in pad)) {  
            pad[args] = self.apply(obj, arguments); 
        }  
        return pad[args]; 
    }  
    memoizedFn.unmemoize = function() {  
        return self; 
    }  
    return memoizedFn; 
    }  
    Function.prototype.unmemoize = function() {  
    alert("Attempt to unmemoize an unmemoized function."); 
    return null; 
   }

使用方法:fib.memoize();

标签:设计模式,JavaScript,接口,组合模式
0
投稿

猜你喜欢

  • Silverlight VS Flash,谁更强?

    2008-11-07 11:04:00
  • jquery表单验证使用插件formValidator

    2023-07-02 05:30:54
  • js放大镜放大图片效果

    2024-04-30 08:51:38
  • python base64库给用户名或密码加密的流程

    2021-01-30 16:30:39
  • 使用pandas模块读取csv文件和excel表格,并用matplotlib画图的方法

    2023-10-04 14:42:58
  • SQL Server 2000如何设置会话上下文信息?

    2010-05-18 18:33:00
  • pycharm运行出现ImportError:No module named的解决方法

    2022-09-10 18:06:23
  • django-rest-framework解析请求参数过程详解

    2023-03-26 18:18:00
  • php之php.ini配置文件讲解案例

    2023-06-11 18:19:06
  • 详解MySQL数据库千万级数据查询和存储

    2024-01-16 18:53:20
  • 如何通过Python3和ssl实现加密通信功能

    2022-04-28 05:55:30
  • 浅谈django不使用restframework自定义接口与使用的区别

    2023-11-24 09:44:02
  • 去掉前面的0的sql语句(前导零,零前缀)

    2011-09-30 11:28:19
  • Python3爬虫中关于Ajax分析方法的总结

    2021-04-07 17:28:47
  • TensorFlow实现Logistic回归

    2023-11-27 18:49:14
  • python的pstuil模块使用方法总结

    2022-10-09 22:47:16
  • django ListView的使用 ListView中获取url中的参数值方式

    2022-06-17 10:41:57
  • SQL Server 2008升级报表服务器数据库

    2008-11-18 12:36:00
  • 深入Golang中的sync.Pool详解

    2024-02-02 05:31:27
  • 分享10个Js的小型库,效果真的很棒

    2009-08-27 15:38:00
  • asp之家 网络编程 m.aspxhome.com