小议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();


猜你喜欢
- 看了OReilly.JavaScript.The.Definitive.Guide.5th.Edition.Aug.2006里的cookie
- Python 代码库之Tuple如何append元素tuple不像array给我们提供了append函数,我们可以通过下面的方式添加t=[1
- python烟花代码如下# -*- coding: utf-8 -*-import math, random,timeimport thre
- 我正在开发一个档案管理系统,需要从数据库中同时调出图像及相关的文字说明,可我只做到了单纯地显示图片,像有一个数据库CHUNFENG,在数据库
- 下载opencv2.4.9(python2.7匹配)后 (1)运行OpenCV 2.4.9.exe;(2)配置Python:将\opencv
- 认识模块对于模块,在前面的一些举例中,已经涉及到了,比如曾经有过:import random (获取随机数模块)。为了能够对模块有一个清晰的
- SQL2000的SA密码不能更改的解决方法,在更改sa的密码出现下面的错误:Error 21776: [SQL-DMO] The name
- 在介绍Python的self用法之前,先来介绍下Python中的类和实例……我们知道,面向对象最
- 背景Translation插件在mac上idea能够搜索到,但是在windows上却搜索不到解决勾选上成功了。来源:https://blog
- 现在的离线浏览器很多,可是多数都是共享软件,或是英文软件,这给我们的操作带来了很大的不便。其实微软的网页制作工具FrontPage XP有一
- 收集所有外部链接的网站爬虫程序流程图下例是爬取本站python绘制条形图方法代码详解的实例,大家可以参考下。完整代码:#! /usr/bin
- 序章yield item这行代码会产出一个值,提供给next()的调用方;此外还会做出让步,暂停执行生成器,让调用方继续工作,知道需要使用另
- 最近一直在研究 Javascript 相关的技术。在《Javascript 高级程序设计》有篇章节着重阐述了优化 Javascri
- 开发中经常会使用npm install 安装依赖包,经常会看到^符号和~符号,现将二者的区别总结如下:版本号 x.y.z : z
- 如下所示:#!/usr/bin/env python#-*- coding: utf-8 -*-"""[0,
- 前言字典是 Python 中很重要的数据类型,有很多内置函数需要了解。1.dict.clear清除字典中所有键值对。dict = {'
- 本文实例为大家分享了mysql备份脚本,供大家参考,具体内容如下#!/bin/bash#全备方式,一般在从机上执行,适用于小中型mysql数
- 拼接字符串使用“+”可以对多个字符串进行拼接语法格式: str1 + str2>>> str1 = "aaa&q
- 目录1.程序入口2.__name__是什么?场景1:直接运行脚本场景2:从其他脚本导入3.__name__可以显示包路径5.测试模块里函数关
- 要求:#出租车计费*************************************************************