代码改变世界

以服务器端为中心的 ASP.NET AJAX 模式 (Part 1 - Behavior)

2008-10-26 20:33  Cat Chen  阅读(4742)  评论(12编辑  收藏  举报

早在ASP.NET AJAX从CTP转向Beta再转向RTM时,看着客户端的Control被逐步放弃,与此同时ASP.NET AJAX Control Toolkit越来越多地使用Behavior,我就想深入说说ASP.NET AJAX的模式。不过由于我比较懒,所以这个话题只在《理想的 ASP.NET AJAX (Part 2 - Server Centric)》中一笔带过,没有深入讨论。今天看到volnet的《我们究竟是否有在“Asp.net中模仿Winform的MessageBox ”的必要?》,决定写一个文章系列来说说ASP.NET AJAX的模式。

什么是Behavior?

什么是Behavior?Behavior与Control有什么不同?这是首先需要回答的问题。

在Windows开发当中,Behavior的概念是不存在的,有的只是Control。ASP开发连Control都没有的,到了ASP.NET才引入了Control的概念。为什么Ajax开发要引入Behavior这样的概念呢?因为Behavior意味着不需要改变原有的组件逻辑,而改变原有组件的逻辑在客户端往往是不可行的,至少是难以实现的。

举个最简单的例子,一个<input type=”text” />就是一个浏览器内部的对象,你无法扩展这个对象的类型,也无法为它加上新的属性与方法,至少并非所有浏览器都允许你在JavaScript中这样做。然而如果你想要让它加上auto-complete(或曰suggest)的功能,这是可以做到的,并且很多人都做过了,例如ASP.NET AJAX Control Toolkit的AutoComplete,或者是script.aculo.us的autocompleter。这些实现都基于同一种方式,就是尝试基于input已有的接口在它之外添加新功能,而非尝试继承input并在它之内添加功能。

类似的做法在Ajax开发中普遍存在。例如说拖放吧,现在离HTML5拖放的全面普及不知道还有多远,所以大家都只能基于现有的鼠标事件来开发拖放功能。又或者说带有验证功能的输入框,无论是input还是select,无论是客户端验证还是服务器端验证,也都是基于现有HTML元素的事件来完成的。这一切都是Behavior。

什么情况下使用Behavior?

简单归纳,就两个条件:

  1. 需要基于特定的一个组建进行扩展
  2. 组建本身所处的环境缺乏可扩展性

单看第1个条件,我们有丰富的选择。很多人的第一反应就是继承自该组件,把扩展功能做到子类里面。熟悉设计模式的话,可能还会想到decorator pattern。然而在浏览器的环境当中,受到第2个条件的限制,继承或者decorator pattern都是不可行的。这时候,我们就需要使用Behavior了。

在一定程度上,我们可以把Behavior看作一种折衷了的decorator pattern。在decorator pattern中,decorator也继承自组件,因此当一个组件使用decorator pattern后,我们就把decorator放在原组件所处的位置上,而原组件就成了decorator的一个子节点(基于树的角度来看的话)。如果再加一个decorator,原decorator就会如同一个普通组件那样再被封装一次。在多个decorator的情况下,decorator之间是串联的关系。Behavior本身不是一个浏览器内部的组件,它无法继承自input的基类,因此Behavior也不能串联。Behavior本身本也不会取代input在树中的位置,这使得Behavior可以并联起来——一个input可以有多个Behavior,例如一个是自动完成,另外一个是输入验证。

总之,如果你原来的工作就是和UI打交道,并且熟练使用decorator pattern,那么在进行Ajax开发时把decorator pattern换成Behavior就可以了。

小结

回过头来看文章开头所说的MessageBox(或曰confirm)的问题,如果这个功能不需要对服务器端进行反馈,完全可以使用Behavior实现。ASP.NET AJAX Control Toolkit就有ConfirmButton这样一个东西,在客户端叫Behavior,在服务器端叫Extender,其实Extender就是对Behavior在服务器端做一下封装而已。当然,ConfirmButton不能完全实现MessageBox的功能,它只能在用户选择“取消”时取消整个提交操作,但不能够执行另外一个服务器端的代码分支。这算是Behavior的一个限制,就是它只能在客户端添加额外的功能,但是它不能影响到与服务器端的交互。但很多时候,正是这种限制确保了我们开发的组件是与服务器端解耦的。

如果我真的需要一个与服务器端交互的客户端组件,例如支持调用服务器端代码分支的confirm,怎么办?这时候你就真的需要一个与服务器端Control对应的客户端Control了。请关注本系列的下一篇文章,《以服务器端为中心的 ASP.NET AJAX 模式 (Part 2 – Control)》。通过订阅feed,你可以及时获得文章更新:

P.S.既然提到了Behavior和Extender的一一对应关系,就不得不说一下,服务器端的Extender就是真正的decorator pattern。