javascript几种模式

本文深入探讨了Facade、Adapter、Observer、Singleton、Command及MVC六种设计模式的实际应用案例,展示了如何利用这些模式解决常见的软件设计问题。
闲话少说,直接上代码
(一)Facade模式实例
var net=new Object();
net.READY_STATE_UNINITIALIZED=0;
net.READY_STATE_LOADING=1;
net.READY_STATE_LOADED=2;
net.READY_STATE_INTERACTIVE=3;
net.READY_STATE_COMPLETE=4;
net.ContentLoader=function(url,onload,onerror){
this.url=url;
this.req=null;
this.onload=onload;
this.onerror=(onerror) ? onerror : this.defaultError;
this.loadXMLDoc(url);
net.ContentLoader.prototype={
loadXMLDoc:function(url){
if (window.XMLHttpRequest){
this.req=new XMLHttpRequest();
} else if (window.ActiveXObject){
this.req=new ActiveXObject("Microsoft.XMLHTTP");
}
if (this.req){
try{
var loader=this;
this.req.onreadystatechange=function(){
loader.onReadyState.call(loader);
}
this.req.open('GET',url,true);
this.req.send(null);
}catch (err){
this.onerror.call(this);
}
}
},
onReadyState:function(){
var req=this.req;
var ready=req.readyState;
if (ready==net.READY_STATE_COMPLETE){
var httpStatus=req.status;
if (httpStatus==200 || httpStatus==0){
this.onload.call(this);
}else{
this.onerror.call(this);
}
}
},
defaultError:function(){
alert("error fetching data!"
+"\n\nreadyState:"+this.req.readyState
+"\nstatus: "+this.req.status
+"\nheaders: "+this.req.getAllResponseHeaders());
}
}


(二)Adapter模式实例
var xhr = new XMLHttpRequest();
xhr.open("GET", "myData.xml");
xhr.onreadystatechange = function(){
if(xhr.readyState == 4){
alert(xhr.responseXML);
}
}
xhr.send(null);


(三)Observer模式实例
window.onloadListeners=new Array();
window.addOnLoadListener(listener){
window.onloadListeners[window.onloadListeners.length]=listener;
}

window.onload=function(){
for(var i=0;i<window.onloadListeners.length;i++){
var func=window.onlloadListeners[i];
func.call();
}
}


(四)Singleton模式实例
var SingletonObj = {
property1: value1,
property2: value2,
...
method1:function(){
...
}
method2:function(){
...
}
...
}

function getSingletonObj() {
if(!top.SingletonObj) {
var top.SingletonObj = {
...
}
top.SingletonObj.init(...);
}
return top.SingletonObj;
}


(五)Command模式实例
function buttonOnclickHandler(event){
var data=calculate();
showData(dataTable,data);
}
function ajaxOnloadHandler(){
var data=calculate();
showData(otherDataTable,data);
}
function calculate(){
var data=new Array();
data[0]=6;
data[1]=data[0]/3;
data[2]=data[0]*data[1]+7;
return data;
}
function showData(table,data){
var newRow=createTableRow(table);
for (var i=0;i<data.length;i++){
createTableCell(newRow,data[i]);
}
}
buttonDiv.onclick=buttonOnclickHandler;
poller.onload=ajaxOnloadHandler;

(六)MVC应用实例
function Button(value,domEl){
this.domEl=domEl;
this.value=value;
this.domEl.buttonObj=this;
this.domEl.onclick=this.clickHandler;
}

Button.prototype.clickHandler=function(){
var buttonObj=this.buttonObj;
var value=(buttonObj && buttonObj.value) ?
buttonObj.value : "unknown value";
alert(value);
}


1.跨浏览器不一致性:Facade和Adapter模式
getLeft(e)来自Mike Foster的x库的一个函数简化版本。这个函数接受一个参数e,以一种全面的方式发现这个DOM元素的左边界的像素位置。

Facade的模式:
定义一个函数来隐藏代码,这使得其他代码更加容易阅读,并且将对象检测代码集中到了一个地方。如果发现在某种边界情况下对象检测代码不能正常工作,那么只需要在一个地方修改,就可以将影响扩散到所有调用它的代码中,这就是重构的一个基本原则,
Facade模式可以用来为一个服务或者一些功能的不同实现方式提供公共的访问点。
Adapter模式:
与Facade不同,我们为其中的一个子系统提供了一个额外的层,使得这个子系统展现出与另一个子系统相同的API。这个层称作适配器层(adapter)。
例:用Adapter模式,开发一个控件,使IE的ActiveX控件看起来像是与Mozilla内建的XMLHttpRequest对象一样。


2.管理事件处理函数:Observer模式
Observer模式: 一个操作应该是谁的职责?询问这个问题有些时候是很有帮助的。在这个组合函数的解决方案中,window对象负责获得到DOM元素的引用,随后window对象必须知道当前页面中包括哪些子系统。理想情况下,每个子系统应该自己负责获取它们需要的引用。按照这种方式,如果它包括在页面中,就会获得自己需要的引用;如果没有包括在页面中,就不必做这件事情。

//为了清晰地分离这个职责,可以允许这些系统通过传递一个函数来登记,从而在发生onload事件时得到通知,这些函数会在window.onload事件触发时调用。这里是一个简单的实现:

window.onloadListeners=new Array();
window.addOnLoadListener(listener){
window.onloadListeners[window.onloadListeners.length]=listener;
}


//窗口完全加载后,window对象只需要遍历这个数组,并且依次调用每个方法:

window.onload=function(){
for(var i=0;i<window.onloadListeners.length;i++){
var func=window.onlloadListeners[i];
func.call();
}
}



3 重用用户操作处理函数:Command模式
在面向对象语言的传统Command模式中,用户的交互都封装为Command对象,通常继承自一个基类或者实现一个接口。在这里我们使用一种略微不同的方法来解决相同的问题。因为在JavaScript中,函数本身就是头等对象,我们可以直接将它们当作Command对象来处理,与此同时仍然提供了相同的抽象级别。
将用户所做的事情都封装为Command对象可能看起来有点麻烦,但是这样做是有回报的。当所有的用户行为都封装在Command对象中时,我们就可以很容易地联合使用其他标准的功能。讨论最多的扩展是增加undo()方法,一旦完成了这个工作,就为在整个应用中提供通用的撤销(undo)功能奠定了良好的基础。
在一个更加复杂的例子中,Command在执行时可以被记录在一个栈中,用户可以通过撤销按钮来回退这个栈,从而将应用返回到以前的状态。
每个新的Command对象都放在栈的顶端,可以按顺序逐个回退。用户通过一系列写的操作创建了一个文档,然后选择整个文档时,一不小心点了删除按钮。当调用undo功能时,从栈中弹出最顶端的条目,然后调用它的undo()方法,恢复被删除的文本。后续的撤销操作可能是取消文本的选择,等等。

当然,使用Command模式来创建一个撤销栈,还要确保这些执行和撤销操作的组合能够返回系统的初始状态,对于开发者来说这意味着一些额外的工作。提供完善的撤销功能可以使得产品显得与众不同,特别是对于频繁或长时间使用的应用来说,这个功能更加重要。


4 保持对资源的唯一引用:Singleton模式
一个对象只有一个实例,有时也描述为一个单例(singleton)。
Java中的单例
Java的语言中,实现单例的方法通常是隐藏对象的构造函数,并且提供一个getter方法,基于Java的解决方案利用private和public的访问修饰符来强化单例的行为

JavaScript中的单例
们可以按照平常的方式来定义TradingMode对象:

function TradingMode(){

this.mode=MODE_RED;

}

TradingMode.prototype.setMode=function(){

}


然后提供一个全局变量作为一个伪单例:

TradingMode.instance=new TradingMode();

但是这无法阻止恶意代码调用构造函数。另一方面,我们可以不使用原型,手工创建整个对象:

var TradingMode = new Object();

TradingMode.mode = MODE_RED;

TradingMode.setMode = function() {

...

}


也可以用更加简洁的方式来定义它:


var TradingMode = {

mode:MODE_RED,

setMode:function(){

...

}

};
第1章 简介   模式   JavaScript:基本概念   ECMAScript 5   JSLint   Console   第2章 基本技巧   编写可维护的代码   尽量少用全局变量   for循环   for-in循环   不要增加内置的原型   SWitch模式   避免使用隐式类型转换   使用parseInt()的数值约定   编码约定   命名约定   编写注释   编写API文档   编写可读性强的代码   同行互查   在正式发布时精简代码   运行JSLint   小结   第3章 字面量和构造函数   对象字面量   自定义构造函数   强制使用new的模式   数组字面量   JSON   正则表达式字面量   基本值类型包装器   错误对象   小结   第4章 函数   背景   回调模式   返回函数   自定义函数   即时函数   即时对象初始化   初始化时分支   函数属性——备忘模式   配置对象   Curry   小结   第5章 对象创建模式   命名空间模式   声明依赖关系   私有属性和方法   模块模式   沙箱模式   静态成员   对象常量   链模式   method()方法   小结   第6章 代码复用模式   传统与现代继承模式的比较   使用类式继承时的预期结果   类式继承模式#1——默认模式   类式继承模式#2——借用构造函数   类式继承模式#3——借用和设置原型   类式继承模式#4——共享原型   类式继承模式#5——临时构造函数   Klass   原型继承   通过复制属性实现继承   借用方法   小结   第7章 设计模式   单体模式   工厂模式   迭代器模式   装饰者模式   策略模式   外观模式   代理模式   中介者模式   观察者模式   小结   第8章 DOM和浏览器模式   关注分离   DOM脚本   事件   长期运行脚本   远程脚本   配置JavaScript   载入策略
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值