初次使用Atlas JavaScript (Part 3 - 实现自己的应用)
2006-10-22 15:35 Cat Chen 阅读(951) 评论(0) 编辑 收藏 举报在这里,我假设你肥肥的客户端是基于MVC设计,同时Web Service的内容是以数据为中心的。
在说客户端之前,必须先说说服务器端如何设计。如果服务器端你习惯了3层设计,那就保留你以前的数据访问层和业务逻辑层设计方法,用一模一样的方法完成这两层,只不过我们不再有通过Page表现的UI,而是通过Web Service直接暴露一些业务逻辑层的调用,这就是服务器端需要完成的一切。看起来没有了Page轻松多了,是不是?因为那些工作都转嫁给客户端了。接着要开始用Atlas做我们的客户端了,在这此之前你需要读一下Atlas的各种官方/非官方文档,了解一下它的使用方法,同时读一下它的JavaScript源代码了解一下它的内部结构。
我们首先来看看客户端的Model如何实现,客户端Model应该是用来存储数据并和Web Service打交道,所以它应该设计为一个处于客户端的业务逻辑层。然而这不是一个单纯的业务逻辑层,因为真正的业务逻辑在服务器端,客户端的Model仅仅是在客户端暴露和服务器端业务逻辑层一致的调用。同时它也内涵一个小小的数据访问层,这个数据访问层服务则Web Service打交道,需要包括批量调用和数据缓存与索引等能力。现在我们的分层看起来应该是这样的:
Server Data Access Layer <-> Server Business Layer <-> Client Data Access Layer <-> Client Business Layer
我想肯定有人要问,为什么不把整个业务逻辑层搬到客户端,然后就可省去服务器端的业务逻辑层咯,让客户端的数据访问层和服务器端的数据访问层直接沟通就好了。这样做的最大问题就是,你不知道客户端提交的数据是否一定经过了客户端那个业务逻辑层的处理,用户直接提交一些不符合业务逻辑的数据到服务器端就麻烦了。
继续说我们的客户端Model需要具有的能力。例如服务器端业务层有GetProductById这个方法用于返回一个Product对象,同时客户端的Controller也需要调用此方法,那就应该在客户端的Model暴露GetProductById这个方法。最简单的办法,当然是每次客户端执行GetProductById时,都通过Web Service调用服务器端的GetProductById,然而这却是最低效率的做法。想要提高效率的话,肯定要在客户端缓存数据,这时候客户端就会缓存一些Product对象,而GetProductById方法则需要根据一定的策略决定应该优先搜索缓存还是直接访问Web Service。缓存策略是需要根据应用制定的,什么情况下应该判定缓存过期是没有通则的,这需要你自己去设计。而缓存的方式则有比较固定的做法,就是利用JavaScript特有的关联数组作索引。例如ProductId是Guid,而且使用之前说到的GuidConverter直接转换为String,那就可以创建一个Product.IdIndex对象,然后以ProductId作为关联数组的键来保存Product对象,这样就可以通过Product.IdIndex[ProductId]方法检索一个该ProductId对应的Product对象了。
Model相关的对象,例如Product类和Product.IdIndex对象,可以完全不使用任何Atlas特性,仅仅是普通JavaScript类,因为它们完全不使用Atlas的任何特性都能够好好工作。但你也可以考虑让他们继承自Sys.Component,同时按照Atlas的方式来声明其属性、方法、事件,这样他们能够获得更好的封装性,对debug.dump更好的支持,以及可能更低的执行效率。
然后轮到说View了。View可以说是最简单的部分。说它简单,是因为它和服务器端的View没什么不同,只要你懂得制作服务器端控件,你就知道如何继承Sys.UI.Control制作客户端控件,然后和在Page中一样直接往DOM扔控件就可以了,而且还不需要管SessionState和ViewState这样的东西。有问题吗?例如需要数据,或者有事情需要报告吗?请举手,通过调用或者事件告诉Controller,Controller会通过Model为你处理好这一切,View需要管的仅仅就是用户看得到摸得着的东西。
最后需要搞定的就是Controller了,这时候你有两个选择:使用JavaScript或者使用XmlScript。如果Model和View已经让你写JavaScript写到手痛,那么这时候你可以考虑使用XmlScript来写Controller。你首先把View相关的元素用HTML声明,然后在XmlScript中声明相关的控件以及它们的属性如何绑定到对应的Model对象,那就行了。但如果在Controller里面设计动态创建控件,又或者涉及复杂的数据绑定方式,XmlScript就无法满足你的需求了,这时候还是老老实实地用JavaScript写吧。