ExtJS 设计模式 之一 :单例(singleton)

Posted by totodo on December 29th, 2007

ExtJS 设计模式 之一 (单例)

    Extjs 发展至今,传承了YUI的伟大精髓, YUI得到了Douglas Crockford(任职于 Yahoo! 的一名 JavaScript 传道者和架构师,他是全球最有造诣的 JavaScript 语言专家之一,Blog:http://www.crockford.com/) 大师的赞同,而ExtJS也是将YUI的模式脚本编程学习使用的淋漓尽致,并且还给它做了几套华丽的CSS嫁衣….,   而在ExtJS越发耀眼的同时,我等初学者在使用ExtJs的时候也是晕呼其呼。(好在2.0 推出之后,官方的文档,像雨后春笋一样,开始覆盖到方方面面。)

    其实,拨开ExtJS华丽的外衣,翻阅其体内精致的代码,不难发现一些我们耳熟能详的设计模式。

    在早期1.0,1.1的好多例子中,我们会看到这样风格的代码。

var Oo= function(){
  var x;
  var y;
  return{
  a:function(){
  ...
  },
  b:function(){
  ...
  }
  }
}();

咂一看,不是我们能理解的方式, function(){}(), 是何意?。

//()在这里,意味着方法已经执行,并且return里面的已经产生, 这样可能很难理解,那等同与执行 function oo(){},这样是否好理解些了?

BTW :这里要引入JavaScript的一个高级概念,“闭包”。(具体内容参考《JavaScript The Definitve Guid,5th Eddion》Section 8.8 –Function Scope and Closures ,也是被Douglas Crockford推荐的为数不多的两本书籍之一。), 当然不急着去翻,先把我的废话看完。

    好了,看这种使用别扭的使用方式, 而这种方式,在我们的页面,或者其他类中, 调用Oo的a方法的时候,形式如下

Ext.onReady(Oo.a);

对,正是这样的一种JS编程方式,被Douglas Crockford作为JS的一种单例的实现, 大师还把它叫做“Module Pattern”,

    好,如果我们不用所谓单例呢?, 就看看传统的对象方式,同学们肯定在Pototype盛行的时代,已经弄的一清二楚。

0o = function(){
  this.x;
  this.y;
}
Oo.prototype = {
  a:function(){
  this.x = 100;
  },
  b:function(){
  this.y = 200;
  }
}
//调用方式
Ext.onReady(function(){
  var o = new Oo();
  0.a();
});

    再来,假使是个初学者,不知道对象继承,怎么办。更土的写法,人人都会。

var x,y
function a(){
  x=100;
}
function b(){
  y=200;
}

调用方式。
不用说了,只要a(),就会把x设置, 全世界的开发者都公认 ,全局变量是邪恶的,,而且随着你调用的不注意,将会越来越臃肿,导致Memory Lacks 内存泄露。

    以上几个简单的举例可以看出, 类 比Java 一样, Oo.a直接调用,好比一个静态类,直接访问。 而prototype需要创建对象后访问其成员。
第一种方式,在任何地方都不需要创建(只创建一次),
而第二种方式,需要在每次调用的时候,创建对象。
第三种老土的代码,希望大家尽量少写,这不是程序员风格的体现。

   对于发展到今天,如此庞大的ExtJS2.0,自然也要考虑道自己的运行和调用不要让new 变得太臃肿,在ExtJS中我们发现, 在会被各个组件大量频繁调用到的一些工具类中,单例运用较为频繁。

  Ext 源码中,设计使用单利的代码片段。

//source/core/DomHelper.js
Ext.DomHelper= function() {
  //private attributes
  ..
  return{

}
}();

//source/core/DomQuery.js
Ext.DomQuery =fucntion(){

}();

后记: 由于JavaScript,具有prototype,call,apply来实现继承,面向对象来开发,又有闭包等特性来进行函数编程。有函数编程和面向对象的双重性质, 使得JavaScript格外的灵活,难以驽驾, 开发者选择多种风格来进行编码,在一个整体项目会容易会走向凌乱和灭亡。 这就更需要我们从大师的经验总结,以及ExtJS这种优秀的设计中,去体味学习,站在巨人的肩膀上前进…..

(另外值得一提出的,ExtJs必须要求你的页面为XHTML,当你在别的浏览器下跑的非常顺畅,而唯独IE下有那么点瑕疵(不是脚本报错的),你应当检查下你是否把你的页面定义成XHTML.)。

exjs dwr spring 强强联姻

Posted by admin on July 15th, 2007

ExtJs 在Web UI已经获得很大的殊荣,但单凭借它 Client UI 还无法霸占BS 那么丰富的应用。。他还要选择 一个Web层与后台一起来交互完成一个完美的系统。

Extjs的天生丽质的, 完美了融合JQuery,Prototype,YUI, 和她结合当然也需要出类拔萃,生出名门。 如果采用Java为开发主语言,那么 ExtJS + DWR + SPRING 算是门当户对。

可惜Extjs 的DataStore 的 prxy 并没有DWR一席,因为DWR返回的是Java对象与JSON非常像, 然而DWR 的在于它与Web远程Java方法的直接会话,因此有着非常灵活的一面。所以,有时候使用DWR对于J2EE来说,要更好于JSON,他做了JSON做不到事。

extjs官方论坛里已经有人编写了这样的扩展,后经人丰富,现在基本能满足要求了。
DWR扩展代码如下,创建 Ext.data.DWRProxy类。同样也继承Ext.data.DataProxy ,拿来show着解读一下。

//dwr.js

Ext.data.DWRProxy = function(dwrCall, pagingAndSort){
Ext.data.DWRProxy.superclass.constructor.call(this);
this.dwrCall = dwrCall;
//this.args = args;
this.pagingAndSort = (pagingAndSort!=undefined ? pagingAndSort : true);
};

Ext.extend(Ext.data.DWRProxy, Ext.data.DataProxy, {
load : function(params, reader, callback, scope, arg) {
if(this.fireEvent("beforeload", this, params) !== false) {
var sort;
if(params.sort && params.dir) sort = params.sort + ' ' + params.dir;
else sort = '';
var delegate = this.loadResponse.createDelegate(this, [reader, callback, scope, arg], 1);
var callParams = new Array();
if(arg.arg) {
callParams = arg.arg.slice();
}

if(this.pagingAndSort) {
callParams.push(params.start);
callParams.push(params.limit);
callParams.push(sort);
}

callParams.push(delegate);
this.dwrCall.apply(this, callParams);
} else {
callback.call(scope || this, null, arg, false);
}
},

loadResponse : function(listRange, reader, callback, scope, arg) {
var result;
try {
result = reader.read(listRange);
} catch(e) {
this.fireEvent("loadexception", this, null, response, e);
callback.call(scope, null, arg, false);
return;
}
callback.call(scope, result, arg, true);
},

update : function(dataSet){},

updateResponse : function(dataSet)
{}
});

Ext.data.ListRangeReader = function(meta, recordType){
Ext.data.ListRangeReader.superclass.constructor.call(this, meta, recordType);
this.recordType = recordType;
};
Ext.extend(Ext.data.ListRangeReader, Ext.data.DataReader, {
getJsonAccessor: function(){
var re = /[\[\.]/;
return function(expr) {
try {
return(re.test(expr))
? new Function("obj", "return obj." + expr)
: function(obj){
return obj[expr];
};
} catch(e){}
return Ext.emptyFn;
};
}(),

read : function(o){
var recordType = this.recordType, fields = recordType.prototype.fields;

//Generate extraction functions for the totalProperty, the root, the id, and for each field
if (!this.ef) {
if(this.meta.totalProperty) {
this.getTotal = this.getJsonAccessor(this.meta.totalProperty);
}

if(this.meta.successProperty) {
this.getSuccess = this.getJsonAccessor(this.meta.successProperty);
}

if (this.meta.id) {
var g = this.getJsonAccessor(this.meta.id);
this.getId = function(rec) {
var r = g(rec);
return (r === undefined || r === "") ? null : r;
};
} else {
this.getId = function(){return null;};
}
this.ef = [];
for(var i = 0; i < fields.length; i++){
f = fields.items[i];
var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
this.ef[i] = this.getJsonAccessor(map);
}
}

var records = [];
var root = o.data, c = root.length, totalRecords = c, success = true;

if(this.meta.totalProperty){
var v = parseInt(this.getTotal(o), 10);
if(!isNaN(v)){
totalRecords = v;
}
}

if(this.meta.successProperty){
var v = this.getSuccess(o);
if(v === false || v === 'false'){
success = false;
}
}

for(var i = 0; i < c; i++){
var n = root[i];
var values = {};
var id = this.getId(n);
for(var j = 0; j < fields.length; j++){
f = fields.items[j];
var v = this.ef[j](n);
values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
}
var record = new recordType(values, id);
records[i] = record;
}

return {
success : success,
records : records,
totalRecords : totalRecords
};
}
});

经过改造之后,那么DWR可以像JSON一样,返回的数据作为DataStore
代码片断

ds = new Ext.data.Store({
proxy: new Ext.data.DWRProxy(TodoService.getItems, true),
//TotoService.getItems dwr开放出来的Java获取数据方法
reader: new Ext.data.ListRangeReader(
{id:'id', totalProperty:'totalSize'}, recordType),
remoteSort: true
});

Spring实现了强大的管理了后台的JavaBean,干干净净的注入创建了每个对象, DWR天生又是支持Spring,无缝的讲Spring的后台Bean 发布到Web层作为JavaScript对象,和JavaScript方法。中途不需要人工干预写Servlet.

不多说了, 跑了下代码,通过,可以直接下载。
download/ext-dwr-spring.rar